diff options
| -rw-r--r-- | changes/feature_osx-eip-rewrite | 2 | ||||
| -rw-r--r-- | pkg/osx/Info.plist | 22 | ||||
| -rw-r--r-- | pkg/osx/Makefile | 51 | ||||
| -rw-r--r-- | pkg/osx/README.rst | 52 | ||||
| -rwxr-xr-x | pkg/osx/build_tuntaposx | 45 | ||||
| -rw-r--r-- | pkg/osx/install/ProcessNetworkChanges.plist.template | 16 | ||||
| -rwxr-xr-x | pkg/osx/install/client.down.sh | 146 | ||||
| -rwxr-xr-x | pkg/osx/install/client.up.sh | 596 | ||||
| -rwxr-xr-x | pkg/osx/install/install-leapc.sh | 42 | ||||
| -rw-r--r-- | pkg/osx/install/leap-installer.platypus | 90 | ||||
| -rw-r--r-- | pkg/osx/install/tun.kext/Info.plist | 36 | ||||
| -rw-r--r-- | pkg/osx/leap-client.spec | 36 | ||||
| m--------- | pkg/osx/tuntaposx | 0 | ||||
| -rw-r--r-- | pkg/requirements-dev.pip | 14 | ||||
| -rw-r--r-- | pkg/requirements.pip | 13 | ||||
| -rw-r--r-- | src/leap/config/prefixers.py | 22 | ||||
| -rw-r--r-- | src/leap/gui/wizard.py | 4 | ||||
| -rw-r--r-- | src/leap/services/eip/vpn.py | 11 | ||||
| -rw-r--r-- | src/leap/services/eip/vpnlaunchers.py | 118 | 
19 files changed, 1304 insertions, 12 deletions
| diff --git a/changes/feature_osx-eip-rewrite b/changes/feature_osx-eip-rewrite new file mode 100644 index 00000000..b47b76a9 --- /dev/null +++ b/changes/feature_osx-eip-rewrite @@ -0,0 +1,2 @@ + o Working packaging workflow with rewritten client, using pyinstaller +   and platypus. diff --git a/pkg/osx/Info.plist b/pkg/osx/Info.plist new file mode 100644 index 00000000..e90d920a --- /dev/null +++ b/pkg/osx/Info.plist @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> +	<key>CFBundleDisplayName</key> +	<string>leap-client</string> +	<key>CFBundleExecutable</key> +	<string>MacOS/app</string> +	<key>CFBundleIconFile</key> +	<string>icon-windowed.icns</string> +	<key>CFBundleInfoDictionaryVersion</key> +	<string>6.0</string> +	<key>CFBundleName</key> +	<string>leap-client</string> +	<key>CFBundlePackageType</key> +	<string>APPL</string> +	<key>CFBundleShortVersionString</key> +	<string>1</string> +	<key>LSBackgroundOnly</key> +	<false/> +</dict> +</plist> diff --git a/pkg/osx/Makefile b/pkg/osx/Makefile new file mode 100644 index 00000000..15dfb810 --- /dev/null +++ b/pkg/osx/Makefile @@ -0,0 +1,51 @@ +OSX = dist/LEAP\ Client.app/Contents/MacOS/ +GITC = `git rev-parse --short HEAD` +DMG = "dist/leap-client-$(GITC).dmg" +INST = "dist/LEAP Client installer.app" +INSTR = "dist/LEAP Client installer.app/Contents/Resources" + +pkg :  check-env dist tuntap installer dmg + +dist : +	~/pyinstaller/pyinstaller.py -w -s leap-client.spec +	cp -r /opt/local/Library/Frameworks/QtGui.framework/Versions/4/Resources/qt_menu.nib "dist/LEAP Client.app/Contents/Resources" +	cp Info.plist "dist/LEAP Client.app/Contents/Info.plist" +	cp ../../data/images/leap-client.icns "dist/LEAP Client.app/Contents/Resources/icon-windowed.icns" + +trim: +	#XXX this should go properly in pyinstaller spec excludes, but going quick'n'dirty +	#XXX adapt to PySide +	rm $(OSX)QtSvg $(OSX)QtXml $(OSX)QtNetwork $(OSX)QtOpenGL $(OSX)Qt3Support $(OSX)QtSql + +tuntap: +	./build_tuntaposx clean && ./build_tuntaposx + +installer: +	#XXX need to fix some paths there (binary, etc) +	platypus -P install/leap-installer.platypus -y $(INST) +	# build tuntaposx kernel extension +	mkdir $(INSTR)/StartupItems +	mkdir $(INSTR)/Extensions +	cp -r dist/tun.kext $(INSTR)/Extensions +	cp -r dist/tuntaposx/StartupItems/* $(INSTR)/StartupItems +	cp install/tun.kext/Info.plist $(INSTR)/Extensions/tun.kext/Contents/ +	#copy the binary that we have previously built (not yet) +	cp ../../openvpn/build/openvpn.leap $(INSTR) +	#copy startup scripts +	cp install/client.up.sh $(INSTR)  +	cp install/client.down.sh $(INSTR) +	cp install/ProcessNetworkChanges.plist.template $(INSTR)  +	#Finally, copy application bundle... +	cp -r "dist/LEAP Client.app" $(INSTR)  + +dmg : +	rm -f $(DMG) +	hdiutil create -format UDBZ -srcfolder $(INST) $(DMG) + +check-env: +ifndef VIRTUAL_ENV +    $(error WHAT DO YOU THINK VIRTUALENV IS FOR??!! Please go get into one..) +endif + +clean : +	rm -rf dist/ build/ diff --git a/pkg/osx/README.rst b/pkg/osx/README.rst new file mode 100644 index 00000000..03aac4f2 --- /dev/null +++ b/pkg/osx/README.rst @@ -0,0 +1,52 @@ +environment setup in osx +======================== +(I rm'd my README by mistake at some point. Re-do). + +basically you need this to setup your environment: + +# check and consolidate + +# install xcode and macports  +# port -v selfupdate +# port install python26 +# port install python_select +# port select python python26 +# port install py26-pyqt4 +# port install py26-pip +# port install py26-virtualenv +# port install git-core +# port install platypus +# port install upx + +Requirements +============ +pyinstaller +----------- +Expected in ~/pyinstaller + +You need the development version. +Tested with: 2.0.373 + +platypus (tested with latest macports) + +... + install environment as usual, +      inside virtualenv. + +Building the package +==================== + +Building the binary +------------------- +We use the scripts in openvpn/build.zsh +The packaging Makefile is expecting the final binary in the location:: + +    ../../openvpn/build/openvpn.leap + +Running the build +----------------- +IMPORTANT: activate the VIRTUALENV FIRST! +(you will get an import error otherwise) + +For running all steps at once:: + +    make pkg diff --git a/pkg/osx/build_tuntaposx b/pkg/osx/build_tuntaposx new file mode 100755 index 00000000..10bb7c9c --- /dev/null +++ b/pkg/osx/build_tuntaposx @@ -0,0 +1,45 @@ +#!/bin/zsh +# +# Copyright (C) 2012 ...  +# + +REPO="https://github.com/bbits/tuntaposx.git" + +autoload colors; colors +# standard output message routines +# it's always useful to wrap them, in case we change behaviour later +notice() { if [[ $QUIET == 0 ]]; then print "$fg_bold[green][*]$fg_no_bold[default] $1" >&2; fi } +error()  { if [[ $QUIET == 0 ]]; then print "$fg[red][!]$fg[default] $1" >&2; fi } +func()   { if [[ $DEBUG == 1 ]]; then print "$fg[blue][D]$fg[default] $1" >&2; fi } +act()    { +    if [[ $QUIET == 0 ]]; then +	if [ "$1" = "-n" ]; then +	    print -n "$fg_bold[white] . $fg_no_bold[default] $2" >&2; +	else +	    print "$fg_bold[white] . $fg_no_bold[default] $1" >&2; +	fi +    fi +} + +{ test "$1" = "clean" } && { +	notice "Cleaning up all tuntaposx build" +	rm -rf tuntaposx +	act "Done." +	return 0 +} + +build_tuntap() { +	test -d tuntaposx || git clone $REPO  +	notice "Cloning tuntaposx sources" +	cd tuntaposx/tuntap +	notice "Building tuntaposx" +	make +	mkdir -p ../../dist/tun.kext +	cp -r tun.kext/* ../../dist/tun.kext +	mkdir -p ../../dist/tuntaposx/StartupItems +	cp -r startup_item/tun ../../dist/tuntaposx/StartupItems +	cd ../.. +} + +act "Building tuntap" +build_tuntap diff --git a/pkg/osx/install/ProcessNetworkChanges.plist.template b/pkg/osx/install/ProcessNetworkChanges.plist.template new file mode 100644 index 00000000..eaf54fcf --- /dev/null +++ b/pkg/osx/install/ProcessNetworkChanges.plist.template @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +	<dict> +		<key>Label</key> +		<string>se.leap.openvpn.process-network-changes</string> +		<key>ProgramArguments</key> +		<array> +			<string>${DIR}/process-network-changes</string> +		</array> +		<key>WatchPaths</key> +		<array> +			<string>/Library/Preferences/SystemConfiguration</string> +		</array> +	</dict> +</plist> diff --git a/pkg/osx/install/client.down.sh b/pkg/osx/install/client.down.sh new file mode 100755 index 00000000..66467c08 --- /dev/null +++ b/pkg/osx/install/client.down.sh @@ -0,0 +1,146 @@ +#!/bin/bash -e +# Note: must be bash; uses bash-specific tricks +# +# ****************************************************************************************************************** +# This Tunnelblick script does everything! It handles TUN and TAP interfaces,  +# pushed configurations and DHCP leases. :) +#  +# This is the "Down" version of the script, executed after the connection is  +# closed. +# +# Created by: Nick Williams (using original code and parts of old Tblk scripts) +#  +# ****************************************************************************************************************** + +trap "" TSTP +trap "" HUP +trap "" INT +export PATH="/bin:/sbin:/usr/sbin:/usr/bin" + +readonly LOG_MESSAGE_COMMAND=$(basename "${0}") + +# Quick check - is the configuration there? +if ! scutil -w State:/Network/OpenVPN &>/dev/null -t 1 ; then +	# Configuration isn't there, so we forget it +	echo "$(date '+%a %b %e %T %Y') *LEAPClient $LOG_MESSAGE_COMMAND: WARNING: No existing OpenVPN DNS configuration found; not tearing down anything; exiting." +	exit 0 +fi + +# NOTE: This script does not use any arguments passed to it by OpenVPN, so it doesn't shift Tunnelblick options out of the argument list + +# Get info saved by the up script +TUNNELBLICK_CONFIG="$(/usr/sbin/scutil <<-EOF +	open +	show State:/Network/OpenVPN +	quit +EOF)" + +ARG_MONITOR_NETWORK_CONFIGURATION="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*MonitorNetwork :' | sed -e 's/^.*: //g')" +LEASEWATCHER_PLIST_PATH="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*LeaseWatcherPlistPath :' | sed -e 's/^.*: //g')" +PSID="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*Service :' | sed -e 's/^.*: //g')" +SCRIPT_LOG_FILE="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*ScriptLogFile :' | sed -e 's/^.*: //g')" +# Don't need: ARG_RESTORE_ON_DNS_RESET="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*RestoreOnDNSReset :' | sed -e 's/^.*: //g')" +# Don't need: ARG_RESTORE_ON_WINS_RESET="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*RestoreOnWINSReset :' | sed -e 's/^.*: //g')" +# Don't need: PROCESS="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*PID :' | sed -e 's/^.*: //g')" +# Don't need: ARG_IGNORE_OPTION_FLAGS="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*IgnoreOptionFlags :' | sed -e 's/^.*: //g')" +ARG_TAP="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*IsTapInterface :' | sed -e 's/^.*: //g')" +bRouteGatewayIsDhcp="$(echo "${TUNNELBLICK_CONFIG}" | grep -i '^[[:space:]]*RouteGatewayIsDhcp :' | sed -e 's/^.*: //g')" + +# @param String message - The message to log +logMessage() +{ +	echo "$(date '+%a %b %e %T %Y') *Tunnelblick $LOG_MESSAGE_COMMAND: "${@} >> "${SCRIPT_LOG_FILE}" +} + +trim() +{ +	echo ${@} +} + +if ${ARG_TAP} ; then +	if [ "$bRouteGatewayIsDhcp" == "true" ]; then +		if [ -z "$dev" ]; then +			logMessage "Cannot configure TAP interface for DHCP without \$dev being defined. Device may not have disconnected properly." +		else +			set +e +			ipconfig set "$dev" NONE 2>/dev/null +			set -e +		fi +	fi +fi + +# Issue warning if the primary service ID has changed +PSID_CURRENT="$( (scutil | grep Service | sed -e 's/.*Service : //')<<- EOF +	open +	show State:/Network/OpenVPN +	quit +EOF)" +if [ "${PSID}" != "${PSID_CURRENT}" ] ; then +	logMessage "Ignoring change of Network Primary Service from ${PSID} to ${PSID_CURRENT}" +fi + +# Remove leasewatcher +if ${ARG_MONITOR_NETWORK_CONFIGURATION} ; then +	launchctl unload "${LEASEWATCHER_PLIST_PATH}" +	logMessage "Cancelled monitoring of system configuration changes" +fi + +# Restore configurations +DNS_OLD="$(/usr/sbin/scutil <<-EOF +	open +	show State:/Network/OpenVPN/OldDNS +	quit +EOF)" +WINS_OLD="$(/usr/sbin/scutil <<-EOF +	open +	show State:/Network/OpenVPN/OldSMB +	quit +EOF)" +TB_NO_SUCH_KEY="<dictionary> { +  TunnelblickNoSuchKey : true +}" + +if [ "${DNS_OLD}" = "${TB_NO_SUCH_KEY}" ] ; then +	scutil <<- EOF +		open +		remove State:/Network/Service/${PSID}/DNS +		quit +EOF +else +	scutil <<- EOF +		open +		get State:/Network/OpenVPN/OldDNS +		set State:/Network/Service/${PSID}/DNS +		quit +EOF +fi + +if [ "${WINS_OLD}" = "${TB_NO_SUCH_KEY}" ] ; then +	scutil <<- EOF +		open +		remove State:/Network/Service/${PSID}/SMB +		quit +EOF +else +	scutil <<- EOF +		open +		get State:/Network/OpenVPN/OldSMB +		set State:/Network/Service/${PSID}/SMB +		quit +EOF +fi + +logMessage "Restored the DNS and WINS configurations" + +# Remove our system configuration data +scutil <<- EOF +	open +	remove State:/Network/OpenVPN/SMB +	remove State:/Network/OpenVPN/DNS +	remove State:/Network/OpenVPN/OldSMB +	remove State:/Network/OpenVPN/OldDNS +	remove State:/Network/OpenVPN +	quit +EOF + +exit 0 diff --git a/pkg/osx/install/client.up.sh b/pkg/osx/install/client.up.sh new file mode 100755 index 00000000..fc7e341a --- /dev/null +++ b/pkg/osx/install/client.up.sh @@ -0,0 +1,596 @@ +#!/bin/bash -e +# Note: must be bash; uses bash-specific tricks +# +# ****************************************************************************************************************** +# This Tunnelblick script does everything! It handles TUN and TAP interfaces,  +# pushed configurations, DHCP with DNS and WINS, and renewed DHCP leases. :) +#  +# This is the "Up" version of the script, executed after the interface is  +# initialized. +# +# Created by: Nick Williams (using original code and parts of old Tblk scripts) +#  +# ****************************************************************************************************************** + +trap "" TSTP +trap "" HUP +trap "" INT +export PATH="/bin:/sbin:/usr/sbin:/usr/bin" + +# Process optional arguments (if any) for the script +# Each one begins with a "-" +# They come from Tunnelblick, and come first, before the OpenVPN arguments +# So we set ARG_ script variables to their values and shift them out of the argument list +# When we're done, only the OpenVPN arguments remain for the rest of the script to use +ARG_MONITOR_NETWORK_CONFIGURATION="false" +ARG_RESTORE_ON_DNS_RESET="false" +ARG_RESTORE_ON_WINS_RESET="false" +ARG_TAP="false" +ARG_IGNORE_OPTION_FLAGS="" + +while [ {$#} ] ; do +	if [ "$1" = "-m" ] ; then						# Handle the arguments we know about +		ARG_MONITOR_NETWORK_CONFIGURATION="true"	# by setting ARG_ script variables to their values +		shift										# Then shift them out +	elif [ "$1" = "-d" ] ; then +		ARG_RESTORE_ON_DNS_RESET="true" +		shift +	elif [ "$1" = "-w" ] ; then +		ARG_RESTORE_ON_WINS_RESET="true" +		shift +	elif [ "$1" = "-a" ] ; then +		ARG_TAP="true" +		shift +	elif [ "${1:0:2}" = "-i" ] ; then +		ARG_IGNORE_OPTION_FLAGS="${1}" +		shift +	elif [ "${1:0:2}" = "-a" ] ; then +		ARG_IGNORE_OPTION_FLAGS="${1}" +		shift +	else +		if [ "${1:0:1}" = "-" ] ; then				# Shift out Tunnelblick arguments (they start with "-") that we don't understand +			shift									# so the rest of the script sees only the OpenVPN arguments +		else +			break +		fi +	fi +done + +readonly ARG_MONITOR_NETWORK_CONFIGURATION ARG_RESTORE_ON_DNS_RESET ARG_RESTORE_ON_WINS_RESET ARG_TAP ARG_IGNORE_OPTION_FLAGS + +# Note: The script log path name is constructed from the path of the regular config file, not the shadow copy +# if the config is shadow copy, e.g. /Library/Application Support/Tunnelblick/Users/Jonathan/Folder/Subfolder/config.ovpn +# then convert to regular config     /Users/Jonathan/Library/Application Support/Tunnelblick/Configurations/Folder/Subfolder/config.ovpn +#      to get the script log path +# Note: "/Users/..." works even if the home directory has a different path; it is used in the name of the log file, and is not used as a path to get to anything. +readonly TBALTPREFIX="/Library/Application Support/Tunnelblick/Users/" +readonly TBALTPREFIXLEN="${#TBALTPREFIX}" +readonly TBCONFIGSTART="${config:0:$TBALTPREFIXLEN}" +if [ "$TBCONFIGSTART" = "$TBALTPREFIX" ] ; then +	readonly TBBASE="${config:$TBALTPREFIXLEN}" +	readonly TBSUFFIX="${TBBASE#*/}" +	readonly TBUSERNAME="${TBBASE%%/*}" +	readonly TBCONFIG="/Users/$TBUSERNAME/Library/Application Support/Tunnelblick/Configurations/$TBSUFFIX" +else +    readonly TBCONFIG="${config}" +fi + +readonly CONFIG_PATH_DASHES_SLASHES="$(echo "${TBCONFIG}" | sed -e 's/-/--/g' | sed -e 's/\//-S/g')" +readonly SCRIPT_LOG_FILE="/Library/Application Support/Tunnelblick/Logs/${CONFIG_PATH_DASHES_SLASHES}.script.log" + +readonly TB_RESOURCE_PATH=$(dirname "${0}") + +LEASEWATCHER_PLIST_PATH="/Library/Application Support/Tunnelblick/LeaseWatch.plist" + +readonly OSVER="$(sw_vers | grep 'ProductVersion:' | grep -o '10\.[0-9]*')" + +readonly DEFAULT_DOMAIN_NAME="openvpn" + +bRouteGatewayIsDhcp="false" + +# @param String message - The message to log +readonly LOG_MESSAGE_COMMAND=$(basename "${0}") +logMessage() +{ +	echo "$(date '+%a %b %e %T %Y') *Tunnelblick $LOG_MESSAGE_COMMAND: "${@} >> "${SCRIPT_LOG_FILE}" +} + +# @param String string - Content to trim +trim() +{ +	echo ${@} +} + +# @param String[] dnsServers - The name servers to use +# @param String domainName - The domain name to use +# @param \optional String[] winsServers - The WINS servers to use +setDnsServersAndDomainName() +{ +	declare -a vDNS=("${!1}") +	domain=$2 +	declare -a vWINS=("${!3}") +	 +	set +e # "grep" will return error status (1) if no matches are found, so don't fail on individual errors +	 +	PSID=$( (scutil | grep PrimaryService | sed -e 's/.*PrimaryService : //')<<- EOF +		open +		show State:/Network/Global/IPv4 +		quit +EOF ) +	 +	STATIC_DNS_CONFIG="$( (scutil | sed -e 's/^[[:space:]]*[[:digit:]]* : //g' | tr '\n' ' ')<<- EOF +		open +		show Setup:/Network/Service/${PSID}/DNS +		quit +EOF )" +	if echo "${STATIC_DNS_CONFIG}" | grep -q "ServerAddresses" ; then +		readonly STATIC_DNS="$(trim "$( echo "${STATIC_DNS_CONFIG}" | sed -e 's/^.*ServerAddresses[^{]*{[[:space:]]*\([^}]*\)[[:space:]]*}.*$/\1/g' )")" +	fi +	if echo "${STATIC_DNS_CONFIG}" | grep -q "SearchDomains" ; then +		readonly STATIC_SEARCH="$(trim "$( echo "${STATIC_DNS_CONFIG}" | sed -e 's/^.*SearchDomains[^{]*{[[:space:]]*\([^}]*\)[[:space:]]*}.*$/\1/g' )")" +	fi +	 +	STATIC_WINS_CONFIG="$( (scutil | sed -e 's/^[[:space:]]*[[:digit:]]* : //g' | tr '\n' ' ')<<- EOF +		open +		show Setup:/Network/Service/${PSID}/SMB +		quit +EOF )" +    STATIC_WINS_SERVERS="" +    STATIC_WORKGROUP="" +    STATIC_NETBIOSNAME="" +    if echo "${STATIC_WINS_CONFIG}" | grep -q "WINSAddresses" ; then +        STATIC_WINS_SERVERS="$(trim "$( echo "${STATIC_WINS_CONFIG}" | sed -e 's/^.*WINSAddresses[^{]*{[[:space:]]*\([^}]*\)[[:space:]]*}.*$/\1/g' )")" +    fi +    if echo "${STATIC_WINS_CONFIG}" | grep -q "Workgroup" ; then +        STATIC_WORKGROUP="$(trim "$( echo "${STATIC_WINS_CONFIG}" | sed -e 's/^.*Workgroup : \([^[:space:]]*\).*$/\1/g' )")" +    fi +    if echo "${STATIC_WINS_CONFIG}" | grep -q "NetBIOSName" ; then +        STATIC_NETBIOSNAME="$(trim "$( echo "${STATIC_WINS_CONFIG}" | sed -e 's/^.*NetBIOSName : \([^[:space:]]*\).*$/\1/g' )")" +    fi +    readonly STATIC_WINS_SERVERS STATIC_WORKGROUP STATIC_NETBIOSNAME +     +	if [ ${#vDNS[*]} -eq 0 ] ; then +		DYN_DNS="false" +		ALL_DNS="${STATIC_DNS}" +	elif [ -n "${STATIC_DNS}" ] ; then +		case "${OSVER}" in +			10.6 | 10.7 ) +				# Do nothing - in 10.6 we don't aggregate our configurations, apparently +				DYN_DNS="false" +				ALL_DNS="${STATIC_DNS}" +				;; +			10.4 | 10.5 ) +				DYN_DNS="true" +				# We need to remove duplicate DNS entries, so that our reference list matches MacOSX's +				SDNS="$(echo "${STATIC_DNS}" | tr ' ' '\n')" +				(( i=0 )) +				for n in "${vDNS[@]}" ; do +					if echo "${SDNS}" | grep -q "${n}" ; then +						unset vDNS[${i}] +					fi +					(( i++ )) +				done +				if [ ${#vDNS[*]} -gt 0 ] ; then +					ALL_DNS="$(trim "${STATIC_DNS}" "${vDNS[*]}")" +				else +					DYN_DNS="false" +					ALL_DNS="${STATIC_DNS}" +				fi +				;; +		esac +	else +		DYN_DNS="true" +		ALL_DNS="$(trim "${vDNS[*]}")" +	fi +	readonly DYN_DNS ALL_DNS + +	if [ ${#vWINS[*]} -eq 0 ] ; then +		DYN_WINS="false" +		ALL_WINS_SERVERS="${STATIC_WINS_SERVERS}" +	elif [ -n "${STATIC_WINS_SERVERS}" ] ; then +		case "${OSVER}" in +			10.6 | 10.7 ) +				# Do nothing - in 10.6 we don't aggregate our configurations, apparently +				DYN_WINS="false" +				ALL_WINS_SERVERS="${STATIC_WINS_SERVERS}" +				;; +			10.4 | 10.5 ) +				DYN_WINS="true" +				# We need to remove duplicate WINS entries, so that our reference list matches MacOSX's +				SWINS="$(echo "${STATIC_WINS_SERVERS}" | tr ' ' '\n')" +				(( i=0 )) +				for n in "${vWINS[@]}" ; do +					if echo "${SWINS}" | grep -q "${n}" ; then +						unset vWINS[${i}] +					fi +					(( i++ )) +				done +				if [ ${#vWINS[*]} -gt 0 ] ; then +					ALL_WINS_SERVERS="$(trim "${STATIC_WINS_SERVERS}" "${vWINS[*]}")" +				else +					DYN_WINS="false" +					ALL_WINS_SERVERS="${STATIC_WINS_SERVERS}" +				fi +				;; +		esac +	else +		DYN_WINS="true" +		ALL_WINS_SERVERS="$(trim "${vWINS[*]}")" +	fi +	readonly DYN_WINS ALL_WINS_SERVERS + +	# We double-check that our search domain isn't already on the list +	SEARCH_DOMAIN="${domain}" +	case "${OSVER}" in +		10.6 | 10.7 ) +			# Do nothing - in 10.6 we don't aggregate our configurations, apparently +			if [ -n "${STATIC_SEARCH}" ] ; then +				ALL_SEARCH="${STATIC_SEARCH}" +				SEARCH_DOMAIN="" +			else +				ALL_SEARCH="${SEARCH_DOMAIN}" +			fi +			;; +		10.4 | 10.5 ) +			if echo "${STATIC_SEARCH}" | tr ' ' '\n' | grep -q "${SEARCH_DOMAIN}" ; then +				SEARCH_DOMAIN="" +			fi +			if [ -z "${SEARCH_DOMAIN}" ] ; then +				ALL_SEARCH="${STATIC_SEARCH}" +			else +				ALL_SEARCH="$(trim "${STATIC_SEARCH}" "${SEARCH_DOMAIN}")" +			fi +			;; +	esac +	readonly SEARCH_DOMAIN ALL_SEARCH + +	if ! ${DYN_DNS} ; then +		NO_DNS="#" +	fi +	if ! ${DYN_WINS} ; then +		NO_WS="#" +	fi +	if [ -z "${SEARCH_DOMAIN}" ] ; then +		NO_SEARCH="#" +	fi +	if [ -z "${STATIC_WORKGROUP}" ] ; then +		NO_WG="#" +	fi +	if [ -z "${STATIC_NETBIOSNAME}" ] ; then +		NO_NB="#" +	fi +	if [ -z "${ALL_DNS}" ] ; then +		AGG_DNS="#" +	fi +	if [ -z "${ALL_SEARCH}" ] ; then +		AGG_SEARCH="#" +	fi +	if [ -z "${ALL_WINS_SERVERS}" ] ; then +		AGG_WINS="#" +	fi +	 +	# Now, do the aggregation +	# Save the openvpn process ID and the Network Primary Service ID, leasewather.plist path, logfile path, and optional arguments from Tunnelblick, +	# then save old and new DNS and WINS settings +	# PPID is a bash-script variable that contains the process ID of the parent of the process running the script (i.e., OpenVPN's process ID) +	# config is an environmental variable set to the configuration path by OpenVPN prior to running this up script +	logMessage "Up to two 'No such key' warnings are normal and may be ignored" +	 +	# If DNS is manually set, it overrides the DHCP setting, which isn't reflected in 'State:/Network/Service/${PSID}/DNS' +	if echo "${STATIC_DNS_CONFIG}" | grep -q "ServerAddresses" ; then +		CORRECT_OLD_DNS_KEY="Setup:" +	else +		CORRECT_OLD_DNS_KEY="State:" +	fi +	 +	# If WINS is manually set, it overrides the DHCP setting, which isn't reflected in 'State:/Network/Service/${PSID}/DNS' +	if echo "${STATIC_WINS_CONFIG}" | grep -q "WINSAddresses" ; then +		CORRECT_OLD_WINS_KEY="Setup:" +	else +		CORRECT_OLD_WINS_KEY="State:" +	fi +	 +    # If we are not expecting any WINS value, add <TunnelblickNoSuchKey : true> to the expected WINS setup +    NO_NOSUCH_KEY_WINS="#" +    if [ "${NO_NB}" = "#" -a "${AGG_WINS}" = "#" -a "${NO_WG}" = "#" ] ; then +        NO_NOSUCH_KEY_WINS="" +    fi +    readonly NO_NOSUCH_KEY_WINS +     +	set -e # We instruct bash that it CAN again fail on errors + +	scutil <<- EOF +		open +		d.init +		d.add PID # ${PPID} +		d.add Service ${PSID} +		d.add LeaseWatcherPlistPath "${LEASEWATCHER_PLIST_PATH}" +		d.add ScriptLogFile         "${SCRIPT_LOG_FILE}" +		d.add MonitorNetwork        "${ARG_MONITOR_NETWORK_CONFIGURATION}" +		d.add RestoreOnDNSReset     "${ARG_RESTORE_ON_DNS_RESET}" +		d.add RestoreOnWINSReset    "${ARG_RESTORE_ON_WINS_RESET}" +		d.add IgnoreOptionFlags     "${ARG_IGNORE_OPTION_FLAGS}" +		d.add IsTapInterface        "${ARG_TAP}" +		d.add RouteGatewayIsDhcp    "${bRouteGatewayIsDhcp}" +		set State:/Network/OpenVPN +		 +		# First, back up the device's current DNS and WINS configurations +		# Indicate 'no such key' by a dictionary with a single entry: "TunnelblickNoSuchKey : true" +		d.init +		d.add TunnelblickNoSuchKey true +		get ${CORRECT_OLD_DNS_KEY}/Network/Service/${PSID}/DNS +		set State:/Network/OpenVPN/OldDNS +		 +		d.init +		d.add TunnelblickNoSuchKey true +		get ${CORRECT_OLD_WINS_KEY}/Network/Service/${PSID}/SMB +		set State:/Network/OpenVPN/OldSMB +		 +		# Second, initialize the new DNS map +		d.init +		${NO_DNS}d.add ServerAddresses * ${vDNS[*]} +		${NO_SEARCH}d.add SearchDomains * ${SEARCH_DOMAIN} +		d.add DomainName ${domain} +		set State:/Network/Service/${PSID}/DNS +		 +		# Third, initialize the WINS map +		d.init +		${NO_NB}d.add NetBIOSName ${STATIC_NETBIOSNAME} +		${NO_WS}d.add WINSAddresses * ${vWINS[*]} +		${NO_WG}d.add Workgroup ${STATIC_WORKGROUP} +		set State:/Network/Service/${PSID}/SMB +		 +		# Now, initialize the maps that will be compared against the system-generated map +		# which means that we will have to aggregate configurations of statically-configured +		# nameservers, and statically-configured search domains +		d.init +		${AGG_DNS}d.add ServerAddresses * ${ALL_DNS} +		${AGG_SEARCH}d.add SearchDomains * ${ALL_SEARCH} +		d.add DomainName ${domain} +		set State:/Network/OpenVPN/DNS +		 +		d.init +		${NO_NB}d.add NetBIOSName ${STATIC_NETBIOSNAME} +		${AGG_WINS}d.add WINSAddresses * ${ALL_WINS_SERVERS} +		${NO_WG}d.add Workgroup ${STATIC_WORKGROUP} +        ${NO_NOSUCH_KEY_WINS}d.add TunnelblickNoSuchKey true +		set State:/Network/OpenVPN/SMB +		 +		# We are done +		quit +EOF +	 +	logMessage "Saved the DNS and WINS configurations for later use" +	 +	if ${ARG_MONITOR_NETWORK_CONFIGURATION} ; then +        if [ "${ARG_IGNORE_OPTION_FLAGS:0:2}" = "-a" ] ; then +            # Generate an updated plist with the path for process-network-changes +            readonly LEASEWATCHER_TEMPLATE_PATH="$(dirname "${0}")/ProcessNetworkChanges.plist.template" +            sed -e "s|\${DIR}|$(dirname "${0}")|g" "${LEASEWATCHER_TEMPLATE_PATH}" > "${LEASEWATCHER_PLIST_PATH}" +            launchctl load "${LEASEWATCHER_PLIST_PATH}" +            logMessage "Set up to monitor system configuration with process-network-changes" +        else +            # Generate an updated plist with the path for leasewatch +            readonly LEASEWATCHER_TEMPLATE_PATH="$(dirname "${0}")/LeaseWatch.plist.template" +            sed -e "s|\${DIR}|$(dirname "${0}")|g" "${LEASEWATCHER_TEMPLATE_PATH}" > "${LEASEWATCHER_PLIST_PATH}" +            launchctl load "${LEASEWATCHER_PLIST_PATH}" +            logMessage "Set up to monitor system configuration with leasewatch" +        fi +	fi +} + +configureDhcpDns() +{ +	# whilst ipconfig will have created the neccessary Network Service keys, the DNS +	# settings won't actually be used by OS X unless the SupplementalMatchDomains key +	# is added +	# ref. <http://lists.apple.com/archives/Macnetworkprog/2005/Jun/msg00011.html> +	# - is there a way to extract the domains from the SC dictionary and re-insert +	#   as SupplementalMatchDomains? i.e. not requiring the ipconfig domain_name call? +	 +	# - wait until we get a lease before extracting the DNS domain name and merging into SC +	# - despite it's name, ipconfig waitall doesn't (but maybe one day it will :-) +	ipconfig waitall +	 +	unset test_domain_name +	unset test_name_server +	 +	set +e # We instruct bash NOT to exit on individual command errors, because if we need to wait longer these commands will fail +	 +	# usually takes at least a few seconds to get a DHCP lease +	sleep 3 +	n=0 +	while [ -z "$test_domain_name" -a -z "$test_name_server" -a $n -lt 5 ] +	do +		logMessage "Sleeping for $n seconds to wait for DHCP to finish setup." +		sleep $n +		n=`expr $n + 1` +		 +		if [ -z "$test_domain_name" ]; then +			test_domain_name=`ipconfig getoption $dev domain_name 2>/dev/null` +		fi +		 +		if [ -z "$test_name_server" ]; then +			test_name_server=`ipconfig getoption $dev domain_name_server 2>/dev/null` +		fi +	done +	 +	sGetPacketOutput=`ipconfig getpacket $dev` +	 +	set -e # We instruct bash that it CAN again fail on individual errors +	 +	#echo "`date` test_domain_name = $test_domain_name, test_name_server = $test_name_server, sGetPacketOutput = $sGetPacketOutput" +	 +	unset aNameServers +	unset aWinsServers +	 +	nNameServerIndex=1 +	nWinsServerIndex=1 +	 +	if [ "$sGetPacketOutput" ]; then +		sGetPacketOutput_FirstLine=`echo "$sGetPacketOutput"|head -n 1` +		#echo $sGetPacketOutput_FirstLine +		 +		if [ "$sGetPacketOutput_FirstLine" == "op = BOOTREPLY" ]; then +			set +e # "grep" will return error status (1) if no matches are found, so don't fail on individual errors +			 +			for tNameServer in `echo "$sGetPacketOutput"|grep "domain_name_server"|grep -Eo "\{([0-9\.]+)(, [0-9\.]+)*\}"|grep -Eo "([0-9\.]+)"`; do +				aNameServers[nNameServerIndex-1]="$(trim "$tNameServer")" +				let nNameServerIndex++ +			done +			 +			for tWINSServer in `echo "$sGetPacketOutput"|grep "nb_over_tcpip_name_server"|grep -Eo "\{([0-9\.]+)(, [0-9\.]+)*\}"|grep -Eo "([0-9\.]+)"`; do +				aWinsServers[nWinsServerIndex-1]="$(trim "$tWINSServer")" +				let nWinsServerIndex++ +			done +			 +			sDomainName=`echo "$sGetPacketOutput"|grep "domain_name "|grep -Eo ": [-A-Za-z0-9\-\.]+"|grep -Eo "[-A-Za-z0-9\-\.]+"` +			sDomainName="$(trim "$sDomainName")" +			 +			if [ ${#aNameServers[*]} -gt 0 -a "$sDomainName" ]; then +				logMessage "Retrieved name server(s) [ ${aNameServers[@]} ], domain name [ $sDomainName ], and WINS server(s) [ ${aWinsServers[@]} ]" +				setDnsServersAndDomainName aNameServers[@] "$sDomainName" aWinsServers[@] +				return 0 +			elif [ ${#aNameServers[*]} -gt 0 ]; then +				logMessage "Retrieved name server(s) [ ${aNameServers[@]} ] and WINS server(s) [ ${aWinsServers[@]} ] and using default domain name [ $DEFAULT_DOMAIN_NAME ]" +				setDnsServersAndDomainName aNameServers[@] "$DEFAULT_DOMAIN_NAME" aWinsServers[@] +				return 0 +			else +				# Should we return 1 here and indicate an error, or attempt the old method? +				logMessage "No useful information extracted from DHCP/BOOTP packet. Attempting legacy configuration." +			fi +			 +			set -e # We instruct bash that it CAN again fail on errors +		else +			# Should we return 1 here and indicate an error, or attempt the old method? +			logMessage "No DHCP/BOOTP packet found on interface. Attempting legacy configuration." +		fi +	fi +	 +	unset sDomainName +	unset sNameServer +	unset aNameServers +	 +	sDomainName=`ipconfig getoption $dev domain_name 2>/dev/null` +	sNameServer=`ipconfig getoption $dev domain_name_server 2>/dev/null` +	 +	sDomainName="$(trim "$sDomainName")" +	sNameServer="$(trim "$sNameServer")" +	 +	declare -a aWinsServers=( ) # Declare empty WINS array to avoid any useless error messages +	 +	if [ "$sDomainName" -a "$sNameServer" ]; then +		aNameServers[0]=$sNameServer +		logMessage "Retrieved name server [ $sNameServer ], domain name [ $sDomainName ], and no WINS servers" +		setDnsServersAndDomainName aNameServers[@] "$sDomainName" aWinsServers[@] +	elif [ "$sNameServer" ]; then +		aNameServers[0]=$sNameServer +		logMessage "Retrieved name server [ $sNameServer ] and no WINS servers, and using default domain name [ $DEFAULT_DOMAIN_NAME ]" +		setDnsServersAndDomainName aNameServers[@] "$DEFAULT_DOMAIN_NAME" aWinsServers[@] +	elif [ "$sDomainName" ]; then +		logMessage "WARNING: Retrieved domain name [ $sDomainName ] but no name servers from OpenVPN (DHCP), which is not sufficient to make network/DNS configuration changes." +		if ${ARG_MONITOR_NETWORK_CONFIGURATION} ; then +			logMessage "Will NOT monitor for other network configuration changes." +		fi +	else +		logMessage "WARNING: No DNS information received from OpenVPN (DHCP), so no network/DNS configuration changes need to be made." +		if ${ARG_MONITOR_NETWORK_CONFIGURATION} ; then +			logMessage "Will NOT monitor for other network configuration changes." +		fi +	fi +	 +	return 0 +} + +configureOpenVpnDns() +{ +	unset vForOptions +	unset vOptions +	unset aNameServers +	unset aWinsServers +	 +	nOptionIndex=1 +	nNameServerIndex=1 +	nWinsServerIndex=1 + +	while vForOptions=foreign_option_$nOptionIndex; [ -n "${!vForOptions}" ]; do +		vOptions[nOptionIndex-1]=${!vForOptions} +		case ${vOptions[nOptionIndex-1]} in +			*DOMAIN* ) +				sDomainName="$(trim "${vOptions[nOptionIndex-1]//dhcp-option DOMAIN /}")" +				;; +			*DNS*    ) +				aNameServers[nNameServerIndex-1]="$(trim "${vOptions[nOptionIndex-1]//dhcp-option DNS /}")" +				let nNameServerIndex++ +				;; +			*WINS*   ) +				aWinsServers[nWinsServerIndex-1]="$(trim "${vOptions[nOptionIndex-1]//dhcp-option WINS /}")" +				let nWinsServerIndex++ +				;; +            *   ) +                logMessage "Unknown: 'foreign_option_${nOptionIndex}' = '${vOptions[nOptionIndex-1]}'" +                ;; +		esac +		let nOptionIndex++ +	done +	 +	if [ ${#aNameServers[*]} -gt 0 -a "$sDomainName" ]; then +		logMessage "Retrieved name server(s) [ ${aNameServers[@]} ], domain name [ $sDomainName ], and WINS server(s) [ ${aWinsServers[@]} ]" +		setDnsServersAndDomainName aNameServers[@] "$sDomainName" aWinsServers[@] +	elif [ ${#aNameServers[*]} -gt 0 ]; then +		logMessage "Retrieved name server(s) [ ${aNameServers[@]} ] and WINS server(s) [ ${aWinsServers[@]} ] and using default domain name [ $DEFAULT_DOMAIN_NAME ]" +		setDnsServersAndDomainName aNameServers[@] "$DEFAULT_DOMAIN_NAME" aWinsServers[@] +	else +		# Should we maybe just return 1 here to indicate an error? Does this mean that something bad has happened? +		logMessage "No DNS information recieved from OpenVPN, so no network configuration changes need to be made." +		if ${ARG_MONITOR_NETWORK_CONFIGURATION} ; then +			logMessage "Will NOT monitor for other network configuration changes." +		fi +	fi +	 +	return 0 +} + +# We sleep here to allow time for OS X to process network settings +sleep 2 + +EXIT_CODE=0 + +if ${ARG_TAP} ; then +	# Still need to do: Look for route-gateway dhcp (TAP isn't always DHCP) +	bRouteGatewayIsDhcp="false" +	if [ -z "${route_vpn_gateway}" -o "$route_vpn_gateway" == "dhcp" -o "$route_vpn_gateway" == "DHCP" ]; then +		bRouteGatewayIsDhcp="true" +	fi +	 +	if [ "$bRouteGatewayIsDhcp" == "true" ]; then +		if [ -z "$dev" ]; then +			logMessage "Cannot configure TAP interface for DHCP without \$dev being defined. Exiting." +			exit 1 +		fi +		 +		ipconfig set "$dev" DHCP +		 +		configureDhcpDns & +	elif [ "$foreign_option_1" == "" ]; then +		logMessage "No network configuration changes need to be made." +		if ${ARG_MONITOR_NETWORK_CONFIGURATION} ; then +			logMessage "Will NOT monitor for other network configuration changes." +		fi +	else +		configureOpenVpnDns +		EXIT_CODE=$? +	fi +else +	if [ "$foreign_option_1" == "" ]; then +		logMessage "No network configuration changes need to be made." +		if ${ARG_MONITOR_NETWORK_CONFIGURATION} ; then +			logMessage "Will NOT monitor for other network configuration changes." +		fi +	else +		configureOpenVpnDns +		EXIT_CODE=$? +	fi +fi + +exit $EXIT_CODE diff --git a/pkg/osx/install/install-leapc.sh b/pkg/osx/install/install-leapc.sh new file mode 100755 index 00000000..ec3c2834 --- /dev/null +++ b/pkg/osx/install/install-leapc.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# LEAP CLient Installer Script. +# +# Copyright (C) 2013 LEAP Encryption Access Project +# +# This file is part of LEAP Client, as +# available from http://leap.se/. This file is free software; +# you can redistribute it and/or modify it under the terms of the GNU +# General Public License (GPL) as published by the Free Software +# Foundation, in version 2 as it comes in the "COPYING" file of the +# LEAP Client distribution. LEAP Client is distributed in the +# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +# + +set -e + +destlibs=/opt/local/lib +leapdir=/Applications/LEAP\ Client.app +leaplibs=${leapdir}/Contents/MacOS +tunstartup=/Library/StartupItems/tun/tun + +echo "Installing LEAP Client in /Applications..." +cp -r "LEAP Client.app" /Applications + +echo "Copying openvpn binary..." +cp -r openvpn.leap /usr/bin  + +echo "Installing tun/tap drivers..." +test -f $tunstartup && $tunstartup stop + +test -d /Library/Extensions || mkdir -p /Library/Extensions +test -d /Library/StartupItems || mkdir -p /Library/StartupItems + +cp -r Extensions/* /Library/Extensions +cp -r StartupItems/* /Library/StartupItems + +echo "Loading tun/tap kernel extension..." + +$tunstartup start + +echo "Installation Finished!" diff --git a/pkg/osx/install/leap-installer.platypus b/pkg/osx/install/leap-installer.platypus new file mode 100644 index 00000000..9150961e --- /dev/null +++ b/pkg/osx/install/leap-installer.platypus @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> +	<key>AcceptsFiles</key> +	<true/> +	<key>AcceptsText</key> +	<false/> +	<key>Authentication</key> +	<true/> +	<key>Author</key> +	<string>Kali Yuga</string> +	<key>BundledFiles</key> +	<array/> +	<key>Creator</key> +	<string>Platypus-4.7</string> +	<key>DeclareService</key> +	<false/> +	<key>Destination</key> +	<string>MyPlatypusApp.app</string> +	<key>DestinationOverride</key> +	<false/> +	<key>DevelopmentVersion</key> +	<false/> +	<key>DocIcon</key> +	<string></string> +	<key>Droppable</key> +	<false/> +	<key>ExecutablePath</key> +	<string>/opt/local/share/platypus/ScriptExec</string> +	<key>FileTypes</key> +	<array> +		<string>****</string> +		<string>fold</string> +	</array> +	<key>IconPath</key> +	<string></string> +	<key>Identifier</key> +	<string>se.leap.LEAPClientInstaller</string> +	<key>Interpreter</key> +	<string>/bin/sh</string> +	<key>InterpreterArgs</key> +	<array/> +	<key>Name</key> +	<string>LEAPClient Installer</string> +	<key>NibPath</key> +	<string>/opt/local/share/platypus/MainMenu.nib</string> +	<key>OptimizeApplication</key> +	<true/> +	<key>Output</key> +	<string>Progress Bar</string> +	<key>RemainRunning</key> +	<true/> +	<key>Role</key> +	<string>Viewer</string> +	<key>ScriptArgs</key> +	<array/> +	<key>ScriptPath</key> +	<string>./install/install-leapc.sh</string> +	<key>Secure</key> +	<false/> +	<key>ShowInDock</key> +	<false/> +	<key>StatusItemDisplayType</key> +	<string>Text</string> +	<key>StatusItemIcon</key> +	<data> +	</data> +	<key>StatusItemTitle</key> +	<string>MyPlatypusApp</string> +	<key>Suffixes</key> +	<array> +		<string>*</string> +	</array> +	<key>TextBackground</key> +	<string>#ffffff</string> +	<key>TextEncoding</key> +	<integer>4</integer> +	<key>TextFont</key> +	<string>Monaco</string> +	<key>TextForeground</key> +	<string>#000000</string> +	<key>TextSize</key> +	<real>10</real> +	<key>UseXMLPlistFormat</key> +	<true/> +	<key>Version</key> +	<string>1.0</string> +</dict> +</plist> diff --git a/pkg/osx/install/tun.kext/Info.plist b/pkg/osx/install/tun.kext/Info.plist new file mode 100644 index 00000000..fb69ba85 --- /dev/null +++ b/pkg/osx/install/tun.kext/Info.plist @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> +	<key>CFBundleDevelopmentRegion</key> +	<string>English</string> +	<key>CFBundleExecutable</key> +	<string>tun</string> +	<key>CFBundleIdentifier</key> +	<string>leap.tun</string> +	<key>CFBundleInfoDictionaryVersion</key> +	<string>6.0</string> +	<key>CFBundleName</key> +	<string>tun</string> +	<key>CFBundlePackageType</key> +	<string>KEXT</string> +	<key>CFBundleShortVersionString</key> +	<string>20120120</string> +	<key>CFBundleSignature</key> +	<string>????</string> +	<key>CFBundleVersion</key> +	<string>1.0</string> +	<key>OSBundleLibraries</key> +	<dict> +		<key>com.apple.kpi.mach</key> +		<string>8.0</string> +		<key>com.apple.kpi.bsd</key> +		<string>8.0</string> +		<key>com.apple.kpi.libkern</key> +		<string>8.0</string> +		<key>com.apple.kpi.unsupported</key> +		<string>8.0</string> +	</dict> +</dict> +</plist> + diff --git a/pkg/osx/leap-client.spec b/pkg/osx/leap-client.spec new file mode 100644 index 00000000..91aa20d6 --- /dev/null +++ b/pkg/osx/leap-client.spec @@ -0,0 +1,36 @@ +# -*- mode: python -*- +a = Analysis(['../../src/leap/app.py'],  +             pathex=[ +		'../../src/leap', +		'/Users/kaliy/leap/leap_client/src/leap-client/pkg/osx'], +             hiddenimports=['atexit', 'leap.common'], +             hookspath=None) +pyz = PYZ(a.pure) +exe = EXE(pyz, +          a.scripts, +          exclude_binaries=1, +          name=os.path.join('build/pyi.darwin/leap-client', 'app'), +          debug=False, +          strip=True, +          upx=True, +          console=False) +coll = COLLECT(exe, +               a.binaries + +	       # this will easitly break if we setup the venv +	       # somewhere else. FIXME +	       [('cacert.pem', '/Users/kaliy/.Virtualenvs/leap-client/lib/python2.6/site-packages/requests-1.1.0-py2.6.egg/requests/cacert.pem', 'DATA'), +		], +               a.zipfiles, +               a.datas, +               strip=True, +               upx=True, +               name=os.path.join('dist', 'app')) +app = BUNDLE(coll, +             name=os.path.join('dist', 'leap-client.app')) + +import sys +if sys.platform.startswith("darwin"): +    app = BUNDLE(coll, +		 name=os.path.join('dist', 'LEAP Client.app'), +                 appname='LEAP Client', +                 version=1) diff --git a/pkg/osx/tuntaposx b/pkg/osx/tuntaposx new file mode 160000 +Subproject 4e07e2e96b092fb3bb9bbf53ae97c0a53f8aed9 diff --git a/pkg/requirements-dev.pip b/pkg/requirements-dev.pip new file mode 100644 index 00000000..d00afd06 --- /dev/null +++ b/pkg/requirements-dev.pip @@ -0,0 +1,14 @@ +# --------------------------- +# -- external requirements -- +# -- during development    -- +# --------------------------- +# +# For temporary work, you can point this to your developer repo. +# consolidated changes will be pushed to pypi and then added +# to the main requirements.pip +# +# NOTE: you have to run pip install -r pkg/requirements.pip for pip +#       to install it. (do it after python setup.py develop and it +#       will only install this) + +-e git+git://github.com/leapcode/leap_pycommon.git@develop#egg=leap.common diff --git a/pkg/requirements.pip b/pkg/requirements.pip index 8bb6ff3f..89917a53 100644 --- a/pkg/requirements.pip +++ b/pkg/requirements.pip @@ -1,7 +1,8 @@  # in order of addition to the project.  # do not change the ordering.  # -PySide  # Use LEAP_VENV_SKIP_PYSIDE to avoid installing it! +PySide +# Use LEAP_VENV_SKIP_PYSIDE to avoid installing it!  jsonschema<=0.8  requests @@ -13,12 +14,4 @@ argparse  python-dateutil  psutil -# -- external requirements -- -# --------------------------- -# temporary, move to official repo and then -# to pypi -# NOTE: you have to run pip install -r pkg/requirements.pip for pip -#       to install it. (do it after python setup.py develop and it -#       will only install this) - --e git+git://github.com/kalikaneko/leap_common.git@develop#egg=leap_common +leap.common diff --git a/src/leap/config/prefixers.py b/src/leap/config/prefixers.py index 557a77ac..5a9b2112 100644 --- a/src/leap/config/prefixers.py +++ b/src/leap/config/prefixers.py @@ -77,6 +77,28 @@ class LinuxPrefixer(Prefixer):          return os.path.join(os.getcwd(), "config") +class DarwinPrefixer(Prefixer): +    """ +    Config prefixer for the Darwin platform +    """ + +    def get_path_prefix(self, standalone=False): +        """ +        Returns the platform dependant path prefixer. +        This method expects an env variable named LEAP_CLIENT_PATH if +        standalone is used. + +        @param standalone: if True it will return the prefix for a +        standalone application. Otherwise, it will return the system +        default for configuration storage. +        @type standalone: bool +        """ +        config_dir = BaseDirectory.xdg_config_home +        if not standalone: +            return config_dir +        return os.getenv("LEAP_CLIENT_PATH", config_dir) + +  if __name__ == "__main__":      try:          abs_prefixer = Prefixer() diff --git a/src/leap/gui/wizard.py b/src/leap/gui/wizard.py index 4e811fb9..dee3b230 100644 --- a/src/leap/gui/wizard.py +++ b/src/leap/gui/wizard.py @@ -435,10 +435,10 @@ class Wizard(QtGui.QWizard):          """          if state == QtCore.Qt.Checked:              self._selected_services = \ -                self._selected_services.union({service}) +                self._selected_services.union(set([service]))          else:              self._selected_services = \ -                self._selected_services.difference({service}) +                self._selected_services.difference(set([service]))      def _populate_services(self):          """ diff --git a/src/leap/services/eip/vpn.py b/src/leap/services/eip/vpn.py index 4ac7f8a2..9d838609 100644 --- a/src/leap/services/eip/vpn.py +++ b/src/leap/services/eip/vpn.py @@ -166,6 +166,7 @@ class VPN(QtCore.QThread):              self._subp.setProcessEnvironment(env)              self._subp.finished.connect(self.process_finished) +            self._subp.finished.connect(self._dump_exitinfo)              self._subp.start(command[:1][0], command[1:])              logger.debug("Waiting for started...")              self._subp.waitForStarted() @@ -181,6 +182,16 @@ class VPN(QtCore.QThread):              logger.warning("Something went wrong while starting OpenVPN: %r" %                             (e,)) +    def _dump_exitinfo(self): +        """ +        SLOT +        TRIGGER: self._subp.finished + +        Prints debug info when quitting the process +        """ +        logger.debug("stdout: %s", self._subp.readAllStandardOutput()) +        logger.debug("stderr: %s", self._subp.readAllStandardError()) +      def _get_openvpn_process(self):          """          Looks for openvpn instances running diff --git a/src/leap/services/eip/vpnlaunchers.py b/src/leap/services/eip/vpnlaunchers.py index e6502813..78db0176 100644 --- a/src/leap/services/eip/vpnlaunchers.py +++ b/src/leap/services/eip/vpnlaunchers.py @@ -214,6 +214,8 @@ class LinuxVPNLauncher(VPNLauncher):          ]          openvpn_configuration = eipconfig.get_openvpn_configuration() + +        # FIXME: sanitize this! --          for key, value in openvpn_configuration.items():              args += ['--%s' % (key,), value] @@ -270,6 +272,122 @@ class LinuxVPNLauncher(VPNLauncher):                  providerconfig.get_path_prefix(),                  "..", "lib")} +class DarwinVPNLauncher(VPNLauncher): +    """ +    VPN launcher for the Darwin Platform +    """ + +    OSASCRIPT_BIN = '/usr/bin/osascript' +    OSX_ASADMIN = "do shell script \"%s\" with administrator privileges" +    OPENVPN_BIN = 'openvpn.leap' +    INSTALL_PATH = "/Applications/LEAPClient.app/" +    # OPENVPN_BIN = "/%s/Contents/Resources/openvpn.leap" % ( +    #   self.INSTALL_PATH,) +    UP_SCRIPT = "/%s/client.up.sh" % (INSTALL_PATH,) +    DOWN_SCRIPT = "/%s/client.down.sh" % (INSTALL_PATH,) + +    # TODO: Add +    # OPENVPN_DOWN_ROOT = "/usr/lib/openvpn/openvpn-down-root.so" + +    def get_vpn_command(self, eipconfig=None, providerconfig=None, +                        socket_host=None, socket_port="unix"): +        """ +        Returns the platform dependant vpn launching command + +        Might raise VPNException. + +        @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 + +        @return: A VPN command ready to be launched +        @rtype: list +        """ +        leap_assert(eipconfig, "We need an eip config") +        leap_assert_type(eipconfig, EIPConfig) +        leap_assert(providerconfig, "We need a provider config") +        leap_assert_type(providerconfig, ProviderConfig) +        leap_assert(socket_host, "We need a socket host!") +        leap_assert(socket_port, "We need a socket port!") + +        openvpn_possibilities = which(self.OPENVPN_BIN) +        if len(openvpn_possibilities) == 0: +            raise OpenVPNNotFoundException() + +        openvpn = openvpn_possibilities[0] +        args = [openvpn] + +        # TODO: handle verbosity + +        gateway_ip = str(eipconfig.get_gateway_ip(0)) +        logger.debug("Using gateway ip %s" % (gateway_ip,)) + +        args += [ +            '--client', +            '--dev', 'tun', +            '--persist-tun', +            '--persist-key', +            '--remote', gateway_ip, '1194', 'udp', +            '--tls-client', +            '--remote-cert-tls', +            'server' +        ] + +        # FIXME: sanitize this! -- + +        openvpn_configuration = eipconfig.get_openvpn_configuration() +        for key, value in openvpn_configuration.items(): +            args += ['--%s' % (key,), value] + +        args += [ +            '--user', getpass.getuser(), +            '--group', grp.getgrgid(os.getgroups()[-1]).gr_name +        ] + +        if socket_port == "unix": +            args += [ +                '--management-client-user', getpass.getuser() +            ] + +        args += [ +            '--management-signal', +            '--management', socket_host, socket_port, +            '--script-security', '2' +        ] + +        if _has_updown_scripts(self.UP_SCRIPT): +            args += [ +                '--up', self.UP_SCRIPT, +            ] +        if _has_updown_scripts(self.DOWN_SCRIPT): +            args += [ +                '--down', self.DOWN_SCRIPT, +                # FIXME add down-plugin +                # '--plugin', self.OPENVPN_DOWN_ROOT, +                # '\'script_type=down %s\'' % self.DOWN_SCRIPT +            ] + +        args += [ +            '--cert', eipconfig.get_client_cert_path(providerconfig), +            '--key', eipconfig.get_client_cert_path(providerconfig), +            '--ca', providerconfig.get_ca_cert_path() +        ] + +        command = self.OSASCRIPT_BIN +        cmd_args = ["-e", self.OSX_ASADMIN % (' '.join(args),)] + +        logger.debug("Running VPN with command:") +        logger.debug("%s %s" % (command, " ".join(cmd_args))) + +        return [command] + cmd_args + +  if __name__ == "__main__":      logger = logging.getLogger(name='leap')      logger.setLevel(logging.DEBUG) | 
