diff options
Diffstat (limited to 'pkg/osx')
| -rw-r--r-- | pkg/osx/Info.plist | 22 | ||||
| -rw-r--r-- | pkg/osx/Makefile | 46 | ||||
| -rw-r--r-- | pkg/osx/README.rst | 60 | ||||
| -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 | 17 | ||||
| -rw-r--r-- | pkg/osx/install/leap-installer.platypus | 90 | ||||
| -rw-r--r-- | pkg/osx/leap-client.spec | 36 | 
9 files changed, 1029 insertions, 0 deletions
| 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..f2520fcf --- /dev/null +++ b/pkg/osx/Makefile @@ -0,0 +1,46 @@ +#WARNING: You need to run this with an activated VIRTUALENV. + +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 :  dist trim 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 +	rm $(OSX)QtSvg $(OSX)QtXml $(OSX)QtNetwork $(OSX)QtOpenGL $(OSX)Qt3Support $(OSX)QtSql + +installer: +	#XXX need to fix some paths there (binary, etc) +	platypus -P install/leap-installer.platypus -y $(INST) +	#XXX should build tuntap extensions ourselves +	mkdir $(INSTR)/StartupItems +	mkdir $(INSTR)/Extensions +	cp -r /opt/local/Library/StartupItems/tun $(INSTR)/StartupItems +	cp -r /opt/local/Library/StartupItems/tap $(INSTR)/StartupItems +	cp -r /opt/local/Library/Extensions/tun.kext $(INSTR)/Extensions +	cp -r /opt/local/Library/Extensions/tap.kext $(INSTR)/Extensions +	#copy the binary that we have previously built +	#XXX not building it 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) + +clean : +	rm -rf dist/ build/ diff --git a/pkg/osx/README.rst b/pkg/osx/README.rst new file mode 100644 index 00000000..48d96ffb --- /dev/null +++ b/pkg/osx/README.rst @@ -0,0 +1,60 @@ +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  # unneeded? +# port install py26-pyqt4 +# port install py26-twisted +# port install py26-pip +# port install py26-virtualenv +# port install git-core +# port install gnutls +# port install platypus + +Requirements +============ +pyinstaller (in ~/pyinstaller) +platypus (tested with latest macports) + +... + install environment as usual, +      inside virtualenv. + +.. note:: there is something missing here, about troubles building gnutls extension, +          I think I ended by symlinking global install via macports. + +Pyinstaller fix for sip api +--------------------------- +We need a workaround for setting the right sip api. +Paste this in the top of pyinstaller/support/rthooks/pyi_rth_qt4plugins.py:: + +    import sip +    sip.setapi('QString', 2) +    sip.setapi('QVariant', 2) + +See www.pyinstaller.org/wiki/Recipe/PyQtChangeApiVersion. + +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/install/ProcessNetworkChanges.plist.template b/pkg/osx/install/ProcessNetworkChanges.plist.template new file mode 100644 index 00000000..faea8dee --- /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>net.tunnelblick.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..47f00ed7 --- /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') *Tunnelblick $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..2ecfc08e --- /dev/null +++ b/pkg/osx/install/install-leapc.sh @@ -0,0 +1,17 @@ +#!/bin/sh +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" +cp -r Extensions/* /Library/Extensions +cp -r StartupItems/* /Library/StartupItems + +echo "Loading tun/tap kernel extension" +/Library/StartupItems/tun/tun start + +echo "Installation Finished!" + +ln -s /Applications/LEAP\ Client.app/ /Volumes/LEAP\ Client\ installer/ 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/leap-client.spec b/pkg/osx/leap-client.spec new file mode 100644 index 00000000..75bf991b --- /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-testbuild/src/leap-client/pkg/osx'], +             hiddenimports=['atexit'], +             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', '../../../../lib/python2.6/site-packages/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) | 
