diff options
Diffstat (limited to 'src/leap/eip/config.py')
-rw-r--r-- | src/leap/eip/config.py | 190 |
1 files changed, 152 insertions, 38 deletions
diff --git a/src/leap/eip/config.py b/src/leap/eip/config.py index ef0f52b4..917871da 100644 --- a/src/leap/eip/config.py +++ b/src/leap/eip/config.py @@ -1,10 +1,12 @@ import logging import os import platform +import re import tempfile from leap import __branding as BRANDING from leap import certs +from leap.util.misc import null_check from leap.util.fileutil import (which, mkdir_p, check_and_fix_urw_only) from leap.base import config as baseconfig @@ -16,6 +18,8 @@ from leap.eip import specs as eipspecs logger = logging.getLogger(name=__name__) provider_ca_file = BRANDING.get('provider_ca_file', None) +_platform = platform.system() + class EIPConfig(baseconfig.JSONLeapConfig): spec = eipspecs.eipconfig_spec @@ -35,9 +39,13 @@ class EIPServiceConfig(baseconfig.JSONLeapConfig): spec = eipspecs.eipservice_config_spec def _get_slug(self): + domain = getattr(self, 'domain', None) + if domain: + path = baseconfig.get_provider_path(domain) + else: + path = baseconfig.get_default_provider_path() return baseconfig.get_config_file( - 'eip-service.json', - folder=baseconfig.get_default_provider_path()) + 'eip-service.json', folder=path) def _set_slug(self): raise AttributeError("you cannot set slug") @@ -49,45 +57,96 @@ def get_socket_path(): socket_path = os.path.join( tempfile.mkdtemp(prefix="leap-tmp"), 'openvpn.socket') - logger.debug('socket path: %s', socket_path) + #logger.debug('socket path: %s', socket_path) return socket_path -def get_eip_gateway(): +def get_eip_gateway(eipconfig=None, eipserviceconfig=None): """ return the first host in eip service config that matches the name defined in the eip.json config file. """ - placeholder = "testprovider.example.org" - eipconfig = EIPConfig() - #import ipdb;ipdb.set_trace() - eipconfig.load() + # XXX eventually we should move to a more clever + # gateway selection. maybe we could return + # all gateways that match our cluster. + + null_check(eipconfig, "eipconfig") + null_check(eipserviceconfig, "eipserviceconfig") + PLACEHOLDER = "testprovider.example.org" + conf = eipconfig.config + eipsconf = eipserviceconfig.config primary_gateway = conf.get('primary_gateway', None) if not primary_gateway: - return placeholder + return PLACEHOLDER - eipserviceconfig = EIPServiceConfig() - eipserviceconfig.load() - eipsconf = eipserviceconfig.get_config() gateways = eipsconf.get('gateways', None) if not gateways: logger.error('missing gateways in eip service config') - return placeholder + return PLACEHOLDER + if len(gateways) > 0: for gw in gateways: - if gw['name'] == primary_gateway: - hosts = gw['hosts'] - if len(hosts) > 0: - return hosts[0] - else: - logger.error('no hosts') + clustername = gw.get('cluster', None) + if not clustername: + logger.error('no cluster name') + return + + if clustername == primary_gateway: + # XXX at some moment, we must + # make this a more generic function, + # and return ports, protocols... + ipaddress = gw.get('ip_address', None) + if not ipaddress: + logger.error('no ip_address') + return + return ipaddress logger.error('could not find primary gateway in provider' 'gateway list') +def get_cipher_options(eipserviceconfig=None): + """ + gathers optional cipher options from eip-service config. + :param eipserviceconfig: EIPServiceConfig instance + """ + null_check(eipserviceconfig, 'eipserviceconfig') + eipsconf = eipserviceconfig.get_config() + + ALLOWED_KEYS = ("auth", "cipher", "tls-cipher") + CIPHERS_REGEX = re.compile("[A-Z0-9\-]+") + opts = [] + if 'openvpn_configuration' in eipsconf: + config = eipserviceconfig.config.get( + "openvpn_configuration", {}) + for key, value in config.items(): + if key in ALLOWED_KEYS and value is not None: + sanitized_val = CIPHERS_REGEX.findall(value) + if len(sanitized_val) != 0: + _val = sanitized_val[0] + opts.append('--%s' % key) + opts.append('%s' % _val) + return opts + +LINUX_UP_DOWN_SCRIPT = "/etc/leap/resolv-update" +OPENVPN_DOWN_ROOT = "/usr/lib/openvpn/openvpn-down-root.so" + + +def has_updown_scripts(): + """ + checks the existence of the up/down scripts + """ + # XXX should check permissions too + is_file = os.path.isfile(LINUX_UP_DOWN_SCRIPT) + if not is_file: + logger.warning( + "Could not find up/down scripts at %s! " + "Risk of DNS Leaks!!!") + return is_file + + def build_ovpn_options(daemon=False, socket_path=None, **kwargs): """ build a list of options @@ -103,6 +162,12 @@ def build_ovpn_options(daemon=False, socket_path=None, **kwargs): # since we will need to take some # things from there if present. + provider = kwargs.pop('provider', None) + eipconfig = EIPConfig(domain=provider) + eipconfig.load() + eipserviceconfig = EIPServiceConfig(domain=provider) + eipserviceconfig.load() + # get user/group name # also from config. user = baseconfig.get_username() @@ -123,18 +188,32 @@ def build_ovpn_options(daemon=False, socket_path=None, **kwargs): opts.append('--verb') opts.append("%s" % verbosity) - # remote + # remote ############################## + # (server, port, protocol) + opts.append('--remote') - gw = get_eip_gateway() + + gw = get_eip_gateway(eipconfig=eipconfig, + eipserviceconfig=eipserviceconfig) logger.debug('setting eip gateway to %s', gw) opts.append(str(gw)) + + # get port/protocol from eipservice too opts.append('1194') + #opts.append('80') opts.append('udp') opts.append('--tls-client') opts.append('--remote-cert-tls') opts.append('server') + # get ciphers ####################### + + ciphers = get_cipher_options( + eipserviceconfig=eipserviceconfig) + for cipheropt in ciphers: + opts.append(str(cipheropt)) + # set user and group opts.append('--user') opts.append('%s' % user) @@ -149,8 +228,13 @@ def build_ovpn_options(daemon=False, socket_path=None, **kwargs): # interface. unix sockets or telnet interface for win. # XXX take them from the config object. - ourplatform = platform.system() - if ourplatform in ("Linux", "Mac"): + if _platform == "Windows": + opts.append('--management') + opts.append('localhost') + # XXX which is a good choice? + opts.append('7777') + + if _platform in ("Linux", "Darwin"): opts.append('--management') if socket_path is None: @@ -158,19 +242,30 @@ def build_ovpn_options(daemon=False, socket_path=None, **kwargs): opts.append(socket_path) opts.append('unix') - if ourplatform == "Windows": - opts.append('--management') - opts.append('localhost') - # XXX which is a good choice? - opts.append('7777') + opts.append('--script-security') + opts.append('2') + + if _platform == "Linux": + if has_updown_scripts(): + opts.append("--up") + opts.append(LINUX_UP_DOWN_SCRIPT) + opts.append("--down") + opts.append(LINUX_UP_DOWN_SCRIPT) + opts.append("--plugin") + opts.append(OPENVPN_DOWN_ROOT) + opts.append("'script_type=down %s'" % LINUX_UP_DOWN_SCRIPT) # certs + client_cert_path = eipspecs.client_cert_path(provider) + ca_cert_path = eipspecs.provider_ca_path(provider) + + # XXX FIX paths for MAC opts.append('--cert') - opts.append(eipspecs.client_cert_path()) + opts.append(client_cert_path) opts.append('--key') - opts.append(eipspecs.client_cert_path()) + opts.append(client_cert_path) opts.append('--ca') - opts.append(eipspecs.provider_ca_path()) + opts.append(ca_cert_path) # we cannot run in daemon mode # with the current subp setting. @@ -178,7 +273,7 @@ def build_ovpn_options(daemon=False, socket_path=None, **kwargs): #if daemon is True: #opts.append('--daemon') - logger.debug('vpn options: %s', opts) + logger.debug('vpn options: %s', ' '.join(opts)) return opts @@ -198,7 +293,7 @@ def build_ovpn_command(debug=False, do_pkexec_check=True, vpnbin=None, # XXX get use_pkexec from config instead. - if platform.system() == "Linux" and use_pkexec and do_pkexec_check: + if _platform == "Linux" and use_pkexec and do_pkexec_check: # check for both pkexec # AND a suitable authentication @@ -218,8 +313,16 @@ def build_ovpn_command(debug=False, do_pkexec_check=True, vpnbin=None, raise eip_exceptions.EIPNoPolkitAuthAgentAvailable command.append('pkexec') + if vpnbin is None: - ovpn = which('openvpn') + if _platform == "Darwin": + # XXX Should hardcode our installed path + # /Applications/LEAPClient.app/Contents/Resources/openvpn.leap + openvpn_bin = "openvpn.leap" + else: + openvpn_bin = "openvpn" + #XXX hardcode for darwin + ovpn = which(openvpn_bin) else: ovpn = vpnbin if ovpn: @@ -235,10 +338,20 @@ def build_ovpn_command(debug=False, do_pkexec_check=True, vpnbin=None, # XXX check len and raise proper error - return [command[0], command[1:]] + if _platform == "Darwin": + OSX_ASADMIN = 'do shell script "%s" with administrator privileges' + # XXX fix workaround for Nones + _command = [x if x else " " for x in command] + # XXX debugging! + # XXX get openvpn log path from debug flags + _command.append('--log') + _command.append('/tmp/leap_openvpn.log') + return ["osascript", ["-e", OSX_ASADMIN % ' '.join(_command)]] + else: + return [command[0], command[1:]] -def check_vpn_keys(): +def check_vpn_keys(provider=None): """ performs an existance and permission check over the openvpn keys file. @@ -246,8 +359,9 @@ def check_vpn_keys(): per provider, containing the CA cert, the provider key, and our client certificate """ - provider_ca = eipspecs.provider_ca_path() - client_cert = eipspecs.client_cert_path() + assert provider is not None + provider_ca = eipspecs.provider_ca_path(provider) + client_cert = eipspecs.client_cert_path(provider) logger.debug('provider ca = %s', provider_ca) logger.debug('client cert = %s', client_cert) |