diff options
Diffstat (limited to 'src/leap/bitmask')
-rw-r--r-- | src/leap/bitmask/services/eip/darwinvpnlauncher.py | 190 | ||||
-rw-r--r-- | src/leap/bitmask/services/eip/linuxvpnlauncher.py | 232 | ||||
-rw-r--r-- | src/leap/bitmask/services/eip/vpnlauncher.py | 290 | ||||
-rw-r--r-- | src/leap/bitmask/services/eip/windowsvpnlauncher.py | 69 |
4 files changed, 781 insertions, 0 deletions
diff --git a/src/leap/bitmask/services/eip/darwinvpnlauncher.py b/src/leap/bitmask/services/eip/darwinvpnlauncher.py new file mode 100644 index 00000000..f3b6bfc8 --- /dev/null +++ b/src/leap/bitmask/services/eip/darwinvpnlauncher.py @@ -0,0 +1,190 @@ +# -*- coding: utf-8 -*- +# darwinvpnlauncher.py +# Copyright (C) 2013 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/>. +""" +Darwin VPN launcher implementation. +""" +import commands +import getpass +import logging +import os + +from leap.bitmask.services.eip.vpnlauncher import VPNLauncher +from leap.bitmask.services.eip.vpnlauncher import VPNLauncherException +from leap.bitmask.util import get_path_prefix + +logger = logging.getLogger(__name__) + + +class EIPNoTunKextLoaded(VPNLauncherException): + pass + + +class DarwinVPNLauncher(VPNLauncher): + """ + VPN launcher for the Darwin Platform + """ + COCOASUDO = "cocoasudo" + # XXX need the good old magic translate for these strings + # (look for magic in 0.2.0 release) + SUDO_MSG = ("Bitmask needs administrative privileges to run " + "Encrypted Internet.") + INSTALL_MSG = ("\"Bitmask needs administrative privileges to install " + "missing scripts and fix permissions.\"") + + INSTALL_PATH = os.path.realpath(os.getcwd() + "/../../") + INSTALL_PATH_ESCAPED = os.path.realpath(os.getcwd() + "/../../") + OPENVPN_BIN = 'openvpn.leap' + OPENVPN_PATH = "%s/Contents/Resources/openvpn" % (INSTALL_PATH,) + OPENVPN_PATH_ESCAPED = "%s/Contents/Resources/openvpn" % ( + INSTALL_PATH_ESCAPED,) + + UP_SCRIPT = "%s/client.up.sh" % (OPENVPN_PATH,) + DOWN_SCRIPT = "%s/client.down.sh" % (OPENVPN_PATH,) + OPENVPN_DOWN_PLUGIN = '%s/openvpn-down-root.so' % (OPENVPN_PATH,) + + UPDOWN_FILES = (UP_SCRIPT, DOWN_SCRIPT, OPENVPN_DOWN_PLUGIN) + OTHER_FILES = [] + + @classmethod + def cmd_for_missing_scripts(kls, frompath): + """ + Returns a command that can copy the missing scripts. + :rtype: str + """ + to = kls.OPENVPN_PATH_ESCAPED + + cmd = "#!/bin/sh\n" + cmd += "mkdir -p {0}\n".format(to) + cmd += "cp '{0}'/* {1}\n".format(frompath, to) + cmd += "chmod 744 {0}/*".format(to) + + return cmd + + @classmethod + def is_kext_loaded(kls): + """ + Checks if the needed kext is loaded before launching openvpn. + + :returns: True if kext is loaded, False otherwise. + :rtype: bool + """ + return bool(commands.getoutput('kextstat | grep "leap.tun"')) + + @classmethod + def _get_icon_path(kls): + """ + Returns the absolute path to the app icon. + + :rtype: str + """ + resources_path = os.path.abspath( + os.path.join(os.getcwd(), "../../Contents/Resources")) + + return os.path.join(resources_path, "leap-client.tiff") + + @classmethod + def get_cocoasudo_ovpn_cmd(kls): + """ + Returns a string with the cocoasudo command needed to run openvpn + as admin with a nice password prompt. The actual command needs to be + appended. + + :rtype: (str, list) + """ + # TODO add translation support for this + sudo_msg = ("Bitmask needs administrative privileges to run " + "Encrypted Internet.") + iconpath = kls._get_icon_path() + has_icon = os.path.isfile(iconpath) + args = ["--icon=%s" % iconpath] if has_icon else [] + args.append("--prompt=%s" % (sudo_msg,)) + + return kls.COCOASUDO, args + + @classmethod + def get_cocoasudo_installmissing_cmd(kls): + """ + Returns a string with the cocoasudo command needed to install missing + files as admin with a nice password prompt. The actual command needs to + be appended. + + :rtype: (str, list) + """ + # TODO add translation support for this + install_msg = ('"Bitmask needs administrative privileges to install ' + 'missing scripts and fix permissions."') + iconpath = kls._get_icon_path() + has_icon = os.path.isfile(iconpath) + args = ["--icon=%s" % iconpath] if has_icon else [] + args.append("--prompt=%s" % (install_msg,)) + + return kls.COCOASUDO, args + + @classmethod + def get_vpn_command(kls, eipconfig, providerconfig, socket_host, + socket_port="unix", openvpn_verb=1): + """ + Returns the OSX implementation for the vpn launching command. + + Might raise: + EIPNoTunKextLoaded, + OpenVPNNotFoundException, + VPNLauncherException. + + :param eipconfig: eip configuration object + :type eipconfig: EIPConfig + :param providerconfig: provider specific configuration + :type providerconfig: ProviderConfig + :param socket_host: either socket path (unix) or socket IP + :type socket_host: str + :param socket_port: either string "unix" if it's a unix socket, + or port otherwise + :type socket_port: str + :param openvpn_verb: the openvpn verbosity wanted + :type openvpn_verb: int + + :return: A VPN command ready to be launched. + :rtype: list + """ + if not kls.is_kext_loaded(): + raise EIPNoTunKextLoaded + + # we use `super` in order to send the class to use + command = super(DarwinVPNLauncher, kls).get_vpn_command( + eipconfig, providerconfig, socket_host, socket_port, openvpn_verb) + + cocoa, cargs = kls.get_cocoasudo_ovpn_cmd() + cargs.extend(command) + command = cargs + command.insert(0, cocoa) + + command.extend(['--setenv', "LEAPUSER", getpass.getuser()]) + + return command + + @classmethod + def get_vpn_env(kls): + """ + Returns a dictionary with the custom env for the platform. + This is mainly used for setting LD_LIBRARY_PATH to the correct + path when distributing a standalone client + + :rtype: dict + """ + return { + "DYLD_LIBRARY_PATH": os.path.join(get_path_prefix(), "..", "lib") + } diff --git a/src/leap/bitmask/services/eip/linuxvpnlauncher.py b/src/leap/bitmask/services/eip/linuxvpnlauncher.py new file mode 100644 index 00000000..c2c28627 --- /dev/null +++ b/src/leap/bitmask/services/eip/linuxvpnlauncher.py @@ -0,0 +1,232 @@ +# -*- coding: utf-8 -*- +# linuxvpnlauncher.py +# Copyright (C) 2013 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/>. +""" +Linux VPN launcher implementation. +""" +import commands +import logging +import os +import subprocess +import time + +from leap.bitmask.config import flags +from leap.bitmask.util import privilege_policies +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.common.check import leap_assert +from leap.bitmask.util import first + +logger = logging.getLogger(__name__) + + +class EIPNoPolkitAuthAgentAvailable(VPNLauncherException): + pass + + +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 + """ + ps = 'ps aux | grep polkit-%s-authentication-agent-1' + opts = (ps % case for case in ['[g]nome', '[k]de']) + is_running = map(lambda l: commands.getoutput(l), opts) + return any(is_running) + + +def _try_to_launch_agent(): + """ + Tries to launch a polkit daemon. + """ + env = None + if flags.STANDALONE is True: + 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. + subprocess.call(["python -m leap.bitmask.util.polkit_agent"], + shell=True, env=env) + except Exception as exc: + logger.exception(exc) + + +class LinuxVPNLauncher(VPNLauncher): + PKEXEC_BIN = 'pkexec' + OPENVPN_BIN = 'openvpn' + OPENVPN_BIN_PATH = os.path.join( + get_path_prefix(), "..", "apps", "eip", OPENVPN_BIN) + + SYSTEM_CONFIG = "/etc/leap" + UP_DOWN_FILE = "resolv-update" + UP_DOWN_PATH = "%s/%s" % (SYSTEM_CONFIG, UP_DOWN_FILE) + + # We assume this is there by our openvpn dependency, and + # we will put it there on the bundle too. + # TODO adapt to the bundle path. + OPENVPN_DOWN_ROOT_BASE = "/usr/lib/openvpn/" + OPENVPN_DOWN_ROOT_FILE = "openvpn-plugin-down-root.so" + OPENVPN_DOWN_ROOT_PATH = "%s/%s" % ( + OPENVPN_DOWN_ROOT_BASE, + OPENVPN_DOWN_ROOT_FILE) + + UP_SCRIPT = DOWN_SCRIPT = UP_DOWN_PATH + UPDOWN_FILES = (UP_DOWN_PATH,) + POLKIT_PATH = LinuxPolicyChecker.get_polkit_path() + OTHER_FILES = (POLKIT_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(0.5) + 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 missing_other_files(kls): + """ + 'Extend' the VPNLauncher's missing_other_files to check if the polkit + files is outdated. If the polkit file that is in OTHER_FILES exists but + is not up to date, it is added to the missing list. + + :returns: a list of missing files + :rtype: list of str + """ + # we use `super` in order to send the class to use + missing = super(LinuxVPNLauncher, kls).missing_other_files() + polkit_file = LinuxPolicyChecker.get_polkit_path() + if polkit_file not in missing: + if privilege_policies.is_policy_outdated(kls.OPENVPN_BIN_PATH): + missing.append(polkit_file) + + return missing + + @classmethod + def get_vpn_command(kls, eipconfig, providerconfig, socket_host, + socket_port="unix", openvpn_verb=1): + """ + Returns the Linux implementation for the vpn launching command. + + Might raise: + EIPNoPkexecAvailable, + EIPNoPolkitAuthAgentAvailable, + OpenVPNNotFoundException, + VPNLauncherException. + + :param eipconfig: eip configuration object + :type eipconfig: EIPConfig + :param providerconfig: provider specific configuration + :type providerconfig: ProviderConfig + :param socket_host: either socket path (unix) or socket IP + :type socket_host: str + :param socket_port: either string "unix" if it's a unix socket, + or port otherwise + :type socket_port: str + :param openvpn_verb: the openvpn verbosity wanted + :type openvpn_verb: int + + :return: A VPN command ready to be launched. + :rtype: list + """ + # we use `super` in order to send the class to use + command = super(LinuxVPNLauncher, kls).get_vpn_command( + eipconfig, providerconfig, socket_host, socket_port, openvpn_verb) + + pkexec = kls.maybe_pkexec() + if pkexec: + command.insert(0, first(pkexec)) + + return command + + @classmethod + def cmd_for_missing_scripts(kls, frompath, pol_file): + """ + Returns a sh script that can copy the missing files. + + :param frompath: The path where the up/down scripts live + :type frompath: str + :param pol_file: The path where the dynamically generated + policy file lives + :type pol_file: str + + :rtype: str + """ + to = kls.SYSTEM_CONFIG + + cmd = '#!/bin/sh\n' + cmd += 'mkdir -p "%s"\n' % (to, ) + cmd += 'cp "%s/%s" "%s"\n' % (frompath, kls.UP_DOWN_FILE, to) + cmd += 'cp "%s" "%s"\n' % (pol_file, kls.POLKIT_PATH) + cmd += 'chmod 644 "%s"\n' % (kls.POLKIT_PATH, ) + + return cmd + + @classmethod + def get_vpn_env(kls): + """ + Returns a dictionary with the custom env for the platform. + This is mainly used for setting LD_LIBRARY_PATH to the correct + path when distributing a standalone client + + :rtype: dict + """ + return { + "LD_LIBRARY_PATH": os.path.join(get_path_prefix(), "..", "lib") + } diff --git a/src/leap/bitmask/services/eip/vpnlauncher.py b/src/leap/bitmask/services/eip/vpnlauncher.py new file mode 100644 index 00000000..935d75f1 --- /dev/null +++ b/src/leap/bitmask/services/eip/vpnlauncher.py @@ -0,0 +1,290 @@ +# -*- coding: utf-8 -*- +# vpnlauncher.py +# Copyright (C) 2013 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/>. +""" +Platform independant VPN launcher interface. +""" +import getpass +import logging +import os +import stat + +from abc import ABCMeta, abstractmethod +from functools import partial + +from leap.bitmask.config import flags +from leap.bitmask.config.leapsettings import LeapSettings +from leap.bitmask.config.providerconfig import ProviderConfig +from leap.bitmask.services.eip.eipconfig import EIPConfig, VPNGatewaySelector +from leap.bitmask.util import first +from leap.bitmask.util import get_path_prefix +from leap.common.check import leap_assert, leap_assert_type +from leap.common.files import which + +logger = logging.getLogger(__name__) + + +class VPNLauncherException(Exception): + pass + + +class OpenVPNNotFoundException(VPNLauncherException): + pass + + +def _has_updown_scripts(path, warn=True): + """ + Checks the existence of the up/down scripts and its + exec bit if applicable. + + :param path: the path to be checked + :type path: str + + :param warn: whether we should log the absence + :type warn: bool + + :rtype: bool + """ + is_file = os.path.isfile(path) + if warn and not is_file: + logger.error("Could not find up/down script %s. " + "Might produce DNS leaks." % (path,)) + + # XXX check if applies in win + is_exe = False + try: + is_exe = (stat.S_IXUSR & os.stat(path)[stat.ST_MODE] != 0) + except OSError as e: + logger.warn("%s" % (e,)) + if warn and not is_exe: + logger.error("Up/down script %s is not executable. " + "Might produce DNS leaks." % (path,)) + return is_file and is_exe + + +def _has_other_files(path, warn=True): + """ + Checks the existence of other important files. + + :param path: the path to be checked + :type path: str + + :param warn: whether we should log the absence + :type warn: bool + + :rtype: bool + """ + is_file = os.path.isfile(path) + if warn and not is_file: + logger.warning("Could not find file during checks: %s. " % ( + path,)) + return is_file + + +class VPNLauncher(object): + """ + Abstract launcher class + """ + __metaclass__ = ABCMeta + + UPDOWN_FILES = None + OTHER_FILES = None + + @classmethod + @abstractmethod + def get_vpn_command(kls, eipconfig, providerconfig, + socket_host, socket_port, openvpn_verb=1): + """ + Returns the platform dependant vpn launching command + + Might raise: + OpenVPNNotFoundException, + VPNLauncherException. + + :param eipconfig: eip configuration object + :type eipconfig: EIPConfig + :param providerconfig: provider specific configuration + :type providerconfig: ProviderConfig + :param socket_host: either socket path (unix) or socket IP + :type socket_host: str + :param socket_port: either string "unix" if it's a unix socket, + or port otherwise + :type socket_port: str + :param openvpn_verb: the openvpn verbosity wanted + :type openvpn_verb: int + + :return: A VPN command ready to be launched. + :rtype: list + """ + leap_assert_type(eipconfig, EIPConfig) + leap_assert_type(providerconfig, ProviderConfig) + + kwargs = {} + if flags.STANDALONE: + kwargs['path_extension'] = os.path.join( + get_path_prefix(), "..", "apps", "eip") + + openvpn_possibilities = which(kls.OPENVPN_BIN, **kwargs) + if len(openvpn_possibilities) == 0: + raise OpenVPNNotFoundException() + + openvpn = first(openvpn_possibilities) + args = [] + + args += [ + '--setenv', "LEAPOPENVPN", "1" + ] + + if openvpn_verb is not None: + args += ['--verb', '%d' % (openvpn_verb,)] + + gateways = [] + leap_settings = LeapSettings() + domain = providerconfig.get_domain() + gateway_conf = leap_settings.get_selected_gateway(domain) + + if gateway_conf == leap_settings.GATEWAY_AUTOMATIC: + gateway_selector = VPNGatewaySelector(eipconfig) + gateways = gateway_selector.get_gateways() + else: + gateways = [gateway_conf] + + if not gateways: + logger.error('No gateway was found!') + raise VPNLauncherException(kls.tr('No gateway was found!')) + + logger.debug("Using gateways ips: {0}".format(', '.join(gateways))) + + for gw in gateways: + args += ['--remote', gw, '1194', 'udp'] + + args += [ + '--client', + '--dev', 'tun', + ############################################################## + # persist-tun makes ping-restart fail because it leaves a + # broken routing table + ############################################################## + # '--persist-tun', + '--persist-key', + '--tls-client', + '--remote-cert-tls', + 'server' + ] + + openvpn_configuration = eipconfig.get_openvpn_configuration() + for key, value in openvpn_configuration.items(): + args += ['--%s' % (key,), value] + + user = getpass.getuser() + + ############################################################## + # The down-root plugin fails in some situations, so we don't + # drop privs for the time being + ############################################################## + # args += [ + # '--user', user, + # '--group', grp.getgrgid(os.getgroups()[-1]).gr_name + # ] + + if socket_port == "unix": # that's always the case for linux + args += [ + '--management-client-user', user + ] + + args += [ + '--management-signal', + '--management', socket_host, socket_port, + '--script-security', '2' + ] + + if _has_updown_scripts(kls.UP_SCRIPT): + args += [ + '--up', '\"%s\"' % (kls.UP_SCRIPT,), + ] + + if _has_updown_scripts(kls.DOWN_SCRIPT): + args += [ + '--down', '\"%s\"' % (kls.DOWN_SCRIPT,) + ] + + ########################################################### + # For the time being we are disabling the usage of the + # down-root plugin, because it doesn't quite work as + # expected (i.e. it doesn't run route -del as root + # when finishing, so it fails to properly + # restart/quit) + ########################################################### + # if _has_updown_scripts(kls.OPENVPN_DOWN_PLUGIN): + # args += [ + # '--plugin', kls.OPENVPN_DOWN_ROOT, + # '\'%s\'' % kls.DOWN_SCRIPT # for OSX + # '\'script_type=down %s\'' % kls.DOWN_SCRIPT # for Linux + # ] + + args += [ + '--cert', eipconfig.get_client_cert_path(providerconfig), + '--key', eipconfig.get_client_cert_path(providerconfig), + '--ca', providerconfig.get_ca_cert_path() + ] + + command_and_args = [openvpn] + args + logger.debug("Running VPN with command:") + logger.debug(" ".join(command_and_args)) + + return command_and_args + + @classmethod + def get_vpn_env(kls): + """ + Returns a dictionary with the custom env for the platform. + This is mainly used for setting LD_LIBRARY_PATH to the correct + path when distributing a standalone client + + :rtype: dict + """ + return {} + + @classmethod + def missing_updown_scripts(kls): + """ + Returns what updown scripts are missing. + + :rtype: list + """ + leap_assert(kls.UPDOWN_FILES is not None, + "Need to define UPDOWN_FILES for this particular " + "launcher before calling this method") + file_exist = partial(_has_updown_scripts, warn=False) + zipped = zip(kls.UPDOWN_FILES, map(file_exist, kls.UPDOWN_FILES)) + missing = filter(lambda (path, exists): exists is False, zipped) + return [path for path, exists in missing] + + @classmethod + def missing_other_files(kls): + """ + Returns what other important files are missing during startup. + Same as missing_updown_scripts but does not check for exec bit. + + :rtype: list + """ + leap_assert(kls.OTHER_FILES is not None, + "Need to define OTHER_FILES for this particular " + "auncher before calling this method") + file_exist = partial(_has_other_files, warn=False) + zipped = zip(kls.OTHER_FILES, map(file_exist, kls.OTHER_FILES)) + missing = filter(lambda (path, exists): exists is False, zipped) + return [path for path, exists in missing] diff --git a/src/leap/bitmask/services/eip/windowsvpnlauncher.py b/src/leap/bitmask/services/eip/windowsvpnlauncher.py new file mode 100644 index 00000000..3f1ed43b --- /dev/null +++ b/src/leap/bitmask/services/eip/windowsvpnlauncher.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- +# windowsvpnlauncher.py +# Copyright (C) 2013 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/>. +""" +Windows VPN launcher implementation. +""" +import logging + +from leap.bitmask.services.eip.vpnlauncher import VPNLauncher +from leap.common.check import leap_assert + +logger = logging.getLogger(__name__) + + +class WindowsVPNLauncher(VPNLauncher): + """ + VPN launcher for the Windows platform + """ + + OPENVPN_BIN = 'openvpn_leap.exe' + + # XXX UPDOWN_FILES ... we do not have updown files defined yet! + # (and maybe we won't) + @classmethod + def get_vpn_command(kls, eipconfig, providerconfig, socket_host, + socket_port="9876", openvpn_verb=1): + """ + Returns the Windows implementation for the vpn launching command. + + Might raise: + OpenVPNNotFoundException, + VPNLauncherException. + + :param eipconfig: eip configuration object + :type eipconfig: EIPConfig + :param providerconfig: provider specific configuration + :type providerconfig: ProviderConfig + :param socket_host: either socket path (unix) or socket IP + :type socket_host: str + :param socket_port: either string "unix" if it's a unix socket, + or port otherwise + :type socket_port: str + :param openvpn_verb: the openvpn verbosity wanted + :type openvpn_verb: int + + :return: A VPN command ready to be launched. + :rtype: list + """ + leap_assert(socket_port != "unix", + "We cannot use unix sockets in windows!") + + # we use `super` in order to send the class to use + command = super(WindowsVPNLauncher, kls).get_vpn_command( + eipconfig, providerconfig, socket_host, socket_port, openvpn_verb) + + return command |