PageRenderTime 112ms CodeModel.GetById 68ms app.highlight 39ms RepoModel.GetById 1ms app.codeStats 0ms

/wpa_supplicant/functions.sh

http://github.com/brinkman83/bashrc
Shell | 1068 lines | 725 code | 149 blank | 194 comment | 75 complexity | 57813804697f518c667b6930e3c7df2d MD5 | raw file
   1#!/bin/sh
   2
   3#####################################################################
   4## Purpose
   5# This file contains common shell functions used by scripts of the
   6# wpasupplicant package to allow ifupdown to manage wpa_supplicant.
   7# It also contains some functions used by wpa_action(8) that allow
   8# ifupdown to be managed by wpa_cli(8) action events.
   9#
  10# This file is provided by the wpasupplicant package.
  11
  12#####################################################################
  13# Copyright (C) 2006 - 2009 Debian/Ubuntu wpasupplicant Maintainers 
  14# <pkg-wpa-devel@lists.alioth.debian.org>
  15#
  16# This program is free software; you can redistribute it and/or
  17# modify it under the terms of the GNU General Public License
  18# as published by the Free Software Foundation; either version 2
  19# of the License, or (at your option) any later version.
  20#
  21# This program is distributed in the hope that it will be useful,
  22# but WITHOUT ANY WARRANTY; without even the implied warranty of
  23# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24# GNU General Public License for more details.
  25#
  26# On Debian GNU/Linux systems, the text of the GPL license,
  27# version 2, can be found in /usr/share/common-licenses/GPL-2.
  28
  29#####################################################################
  30## global variables
  31# wpa_supplicant variables
  32WPA_SUP_BIN="/sbin/wpa_supplicant"
  33WPA_SUP_PNAME="wpa_supplicant"
  34WPA_SUP_PIDFILE="/var/run/wpa_supplicant.${WPA_IFACE}.pid"
  35
  36# wpa_cli variables
  37WPA_CLI_BIN="/sbin/wpa_cli"
  38WPA_CLI_PNAME="wpa_cli"
  39WPA_CLI_PIDFILE="/var/run/wpa_action.${WPA_IFACE}.pid"
  40WPA_CLI_LOGFILE="/var/log/wpa_action.${WPA_IFACE}.log"
  41WPA_CLI_TIMESTAMP="/var/run/wpa_action.${WPA_IFACE}.timestamp"
  42WPA_CLI_IFUPDOWN="/var/run/wpa_action.${WPA_IFACE}.ifupdown"
  43
  44# sendsigs omission interface, present in initscripts (>= 2.86.ds1-48)
  45if [ -d /lib/init/rw/sendsigs.omit.d/ ]; then
  46	# Debian
  47	WPA_SUP_OMIT_PIDFILE="/lib/init/rw/sendsigs.omit.d/wpasupplicant.wpa_supplicant.${WPA_IFACE}.pid"
  48	WPA_CLI_OMIT_PIDFILE="/lib/init/rw/sendsigs.omit.d/wpasupplicant.wpa_action.${WPA_IFACE}.pid"
  49elif [ -d /var/run/sendsigs.omit.d/ ]; then
  50	# Ubuntu, see https://launchpad.net/bugs/181541 for status
  51	WPA_SUP_OMIT_PIDFILE="/var/run/sendsigs.omit.d/wpasupplicant.wpa_supplicant.${WPA_IFACE}.pid"
  52	WPA_CLI_OMIT_PIDFILE="/var/run/sendsigs.omit.d/wpasupplicant.wpa_action.${WPA_IFACE}.pid"
  53else
  54	WPA_SUP_OMIT_PIDFILE=
  55	WPA_CLI_OMIT_PIDFILE=
  56fi
  57
  58# default ctrl_interface socket directory
  59if [ -z "$WPA_CTRL_DIR" ]; then
  60	WPA_CTRL_DIR="/var/run/wpa_supplicant"
  61fi
  62
  63# verbosity variables
  64if [ -n "$IF_WPA_VERBOSITY" ] || [ "$VERBOSITY" = "1" ]; then
  65	TO_NULL="/dev/stdout"
  66	DAEMON_VERBOSITY="--verbose"
  67else
  68	TO_NULL="/dev/null"
  69	DAEMON_VERBOSITY="--quiet"
  70fi
  71
  72#####################################################################
  73## wpa_cli wrapper
  74# Path to common ctrl_interface socket and iface supplied.
  75# NB: WPA_CTRL_DIR cannot be used for interactive commands, it is
  76# set only in the environment that wpa_cli provides when processing
  77# action events.
  78#
  79wpa_cli () {
  80	"$WPA_CLI_BIN" -p "$WPA_CTRL_DIR" -i "$WPA_IFACE" "$@"
  81
  82	return "$?"
  83}
  84
  85#####################################################################
  86## verbose and stderr message wrapper
  87# Ensures a standard and easily identifiable message is printed by
  88# scripts using this function library.
  89#
  90# verbose	To stdout when IF_WPA_VERBOSITY or VERBOSITY is true
  91#
  92# action	Same as verbose but without newline
  93#		Useful for allowing wpa_cli commands to echo result
  94#		value of 'OK' or 'FAILED'
  95#
  96# stderr	Echo warning or error messages to stderr
  97#
  98# NB: when called by wpa_action, there is no redirection (verbose)
  99#
 100wpa_msg () {
 101	if [ -n "$WPA_ACTION" ]; then
 102		shift
 103		echo "wpa_action: $@"
 104		return
 105	fi
 106	
 107	case "$1" in 
 108		"verbose")
 109			shift
 110			echo "$WPA_SUP_PNAME: $@" >$TO_NULL
 111			;;
 112		"action")
 113			shift
 114			echo -n "$WPA_SUP_PNAME: $@ -- " >$TO_NULL
 115			;;
 116		"stderr")
 117			shift
 118			echo "$WPA_SUP_PNAME: $@" >/dev/stderr
 119			;;
 120		*)
 121			;;
 122	esac
 123}
 124
 125#####################################################################
 126## validate daemon pid files
 127# Test daemon process ID files via start-stop-daemon with a signal 0
 128# given the exec binary and pidfile location.
 129#
 130# $1	daemon
 131# $2	pidfile
 132#
 133# Returns true when pidfile exists, the process ID exists _and_ was
 134# created by the exec binary.
 135#
 136# If the test fails, but the pidfile exists, it is stale
 137#
 138test_daemon_pidfile () {
 139	local DAEMON
 140	local PIDFILE
 141	
 142	if [ -n "$1" ]; then
 143		DAEMON="$1"
 144	fi
 145	
 146	if [ -f "$2" ]; then
 147		PIDFILE="$2"
 148	fi
 149	
 150	if [ -n "$DAEMON" ] && [ -f "$PIDFILE" ]; then
 151		if start-stop-daemon --stop --quiet --signal 0 \
 152			--exec "$DAEMON" --pidfile "$PIDFILE"; then
 153			return 0
 154		else
 155			rm -f "$PIDFILE"
 156			return 1
 157		fi
 158	else
 159		return 1
 160	fi
 161}
 162
 163# validate wpa_supplicant pidfile
 164test_wpa_supplicant () {
 165	test_daemon_pidfile "$WPA_SUP_BIN" "$WPA_SUP_PIDFILE"
 166}
 167
 168# validate wpa_cli pidfile
 169test_wpa_cli () {
 170	test_daemon_pidfile "$WPA_CLI_BIN" "$WPA_CLI_PIDFILE"
 171}
 172
 173#####################################################################
 174## daemonize wpa_supplicant
 175# Start wpa_supplicant via start-stop-dameon with all required
 176# options. Will start if environment variable WPA_SUP_CONF is present
 177#
 178# Default options:
 179# -B	dameonize/background process
 180# -D	driver backend ('wext' if none given)
 181# -P	process ID file
 182# -C	path to ctrl_interface socket directory
 183# -s    log to syslog
 184#
 185# Conditional options:
 186# -c	configuration file
 187# -W	wait for wpa_cli to attach to ctrl_interface socket
 188# -b	bridge interface name
 189# -f	path to log file
 190#
 191init_wpa_supplicant () {
 192	[ -n "$WPA_SUP_CONF" ] || return 0
 193
 194	local WPA_SUP_OPTIONS
 195	WPA_SUP_OPTIONS="-s -B -P $WPA_SUP_PIDFILE -i $WPA_IFACE"
 196
 197	if [ -n "$WPA_ACTION_SCRIPT" ]; then
 198		if [ -x "$WPA_ACTION_SCRIPT" ]; then
 199			WPA_SUP_OPTIONS="$WPA_SUP_OPTIONS -W"
 200			wpa_msg verbose "wait for wpa_cli to attach"
 201		else
 202			wpa_msg stderr "action script \"$WPA_ACTION_SCRIPT\" not executable"
 203			return 1
 204		fi
 205	fi
 206
 207	if [ -n "$IF_WPA_BRIDGE" ]; then
 208		WPA_SUP_OPTIONS="$WPA_SUP_OPTIONS -b $IF_WPA_BRIDGE"
 209		wpa_msg verbose "wpa-bridge $IF_WPA_BRIDGE"
 210	fi
 211
 212	if [ -n "$IF_WPA_DRIVER" ]; then
 213		wpa_msg verbose "wpa-driver $IF_WPA_DRIVER"
 214		case "$IF_WPA_DRIVER" in
 215			hostap|ipw|madwifi|ndiswrapper)
 216				WPA_SUP_OPTIONS="$WPA_SUP_OPTIONS -D wext"
 217				wpa_msg stderr "\"$IF_WPA_DRIVER\" wpa-driver is unsupported"
 218				wpa_msg stderr "using \"wext\" wpa-driver instead ..."
 219				;;
 220			*)
 221				WPA_SUP_OPTIONS="$WPA_SUP_OPTIONS -D $IF_WPA_DRIVER"
 222				;;
 223		esac
 224	else
 225		WPA_SUP_OPTIONS="$WPA_SUP_OPTIONS -D wext"
 226		wpa_msg verbose "using default driver type: wpa-driver wext"
 227	fi
 228
 229	if [ -n "$IF_WPA_DEBUG_LEVEL" ]; then
 230		case "$IF_WPA_DEBUG_LEVEL" in
 231			3)
 232				WPA_SUP_OPTIONS="$WPA_SUP_OPTIONS -t -ddd"
 233				;;
 234			2)
 235				WPA_SUP_OPTIONS="$WPA_SUP_OPTIONS -t -dd"
 236				;;
 237			1)
 238				WPA_SUP_OPTIONS="$WPA_SUP_OPTIONS -t -d"
 239				;;
 240			0)
 241				# wpa_supplicant default verbosity
 242				;;
 243			-1)
 244				WPA_SUP_OPTIONS="$WPA_SUP_OPTIONS -q"
 245				;;
 246			-2)
 247				WPA_SUP_OPTIONS="$WPA_SUP_OPTIONS -qq"
 248				;;
 249		esac
 250		wpa_msg verbose "using debug level: $IF_WPA_DEBUG_LEVEL"
 251	fi
 252
 253	if [ -n "$IF_WPA_LOGFILE" ]; then
 254		# custom log file
 255		WPA_SUP_OPTIONS="$WPA_SUP_OPTIONS -f $IF_WPA_LOGFILE"
 256		WPA_SUP_LOGFILE="$IF_WPA_LOGFILE"
 257		wpa_msg verbose "logging to $IF_WPA_LOGFILE"
 258	fi
 259
 260	wpa_msg verbose "$WPA_SUP_BIN $WPA_SUP_OPTIONS $WPA_SUP_CONF"
 261		
 262	start-stop-daemon --start --oknodo $DAEMON_VERBOSITY \
 263		--name $WPA_SUP_PNAME --startas $WPA_SUP_BIN --pidfile $WPA_SUP_PIDFILE \
 264		-- $WPA_SUP_OPTIONS $WPA_SUP_CONF
 265
 266	if [ "$?" -ne 0 ]; then
 267		wpa_msg stderr "$WPA_SUP_BIN daemon failed to start"
 268		return 1
 269	fi
 270
 271	if [ -n "$WPA_SUP_OMIT_PIDFILE" ]; then
 272		local WPA_PIDFILE_WAIT
 273		local MAX_WPA_PIDFILE_WAIT
 274		WPA_PIDFILE_WAIT="0"
 275		MAX_WPA_PIDFILE_WAIT="5"
 276		until [ -s "$WPA_SUP_PIDFILE" ]; do
 277			if [ "$WPA_PIDFILE_WAIT" -ge "$MAX_WPA_PIDFILE_WAIT" ]; then
 278				wpa_msg stderr "timed out waiting for creation of $WPA_SUP_PIDFILE"
 279				return 1
 280			else
 281				wpa_msg verbose "waiting for \"$WPA_SUP_PIDFILE\": " \
 282					"$WPA_PIDFILE_WAIT (max. $MAX_WPA_PIDFILE_WAIT)"
 283			fi
 284
 285			WPA_PIDFILE_WAIT=$(($WPA_PIDFILE_WAIT + 1))
 286			sleep 1
 287		done
 288		wpa_msg verbose "creating sendsigs omission pidfile: $WPA_SUP_OMIT_PIDFILE"
 289		cat "$WPA_SUP_PIDFILE" > "$WPA_SUP_OMIT_PIDFILE"
 290	else
 291		wpa_msg verbose "sendsigs omission pidfile not created"
 292	fi
 293
 294	local WPA_SOCKET_WAIT
 295	local MAX_WPA_SOCKET_WAIT
 296	WPA_SOCKET_WAIT="0"
 297	MAX_WPA_SOCKET_WAIT="5"
 298	until [ -S "$WPA_CTRL_DIR/$WPA_IFACE" ]; do
 299		if [ "$WPA_SOCKET_WAIT" -ge "$MAX_WPA_SOCKET_WAIT" ]; then
 300			wpa_msg stderr "ctrl_interface socket not found at $WPA_CTRL_DIR/$WPA_IFACE"
 301			return 1
 302		else
 303			wpa_msg verbose "waiting for \"$WPA_CTRL_DIR/$WPA_IFACE\": " \
 304				"$WPA_SOCKET_WAIT (max. $MAX_WPA_SOCKET_WAIT)"
 305		fi
 306		
 307		WPA_SOCKET_WAIT=$(($WPA_SOCKET_WAIT + 1))
 308		sleep 1
 309	done
 310	
 311	wpa_msg verbose "ctrl_interface socket located at $WPA_CTRL_DIR/$WPA_IFACE"
 312}
 313
 314#####################################################################
 315## stop wpa_supplicant process
 316# Kill wpa_supplicant via start-stop-daemon, given the location of
 317# the pidfile or ctrl_interface socket path and interface name
 318#
 319kill_wpa_supplicant () {
 320	test_wpa_supplicant || return 0
 321
 322	wpa_msg verbose "terminating $WPA_SUP_PNAME daemon via pidfile $WPA_SUP_PIDFILE"
 323
 324	start-stop-daemon --stop --oknodo $DAEMON_VERBOSITY \
 325		--exec $WPA_SUP_BIN --pidfile $WPA_SUP_PIDFILE
 326
 327	if [ -f "$WPA_SUP_PIDFILE" ]; then
 328		rm -f "$WPA_SUP_PIDFILE"
 329	fi
 330
 331	if [ -f "$WPA_SUP_OMIT_PIDFILE" ]; then
 332		wpa_msg verbose "removing $WPA_SUP_OMIT_PIDFILE"
 333		rm -f "$WPA_SUP_OMIT_PIDFILE"
 334	fi
 335}
 336
 337#####################################################################
 338## reload wpa_supplicant process
 339# Sending a HUP signal causes wpa_supplicant to reparse its
 340# configuration file
 341#
 342reload_wpa_supplicant () {
 343	if test_wpa_supplicant; then
 344		wpa_msg verbose "reloading wpa_supplicant configuration file via HUP signal"
 345		start-stop-daemon --stop --signal HUP \
 346			--name "$WPA_SUP_PNAME" --pidfile "$WPA_SUP_PIDFILE"
 347	else
 348		wpa_msg verbose "cannot $WPA_ACTION, $WPA_SUP_PIDFILE does not exist"
 349	fi
 350}
 351
 352#####################################################################
 353## daemonize wpa_cli and action script
 354# If environment variable WPA_ACTION_SCRIPT is present, wpa_cli will
 355# be spawned via start-stop-daemon
 356#
 357# Required options:
 358# -a	action script => wpa_action
 359# -P	process ID file
 360# -B	background process
 361#
 362init_wpa_cli () {
 363	[ -n "$WPA_ACTION_SCRIPT" ] || return 0
 364
 365	local WPA_CLI_OPTIONS
 366	WPA_CLI_OPTIONS="-B -P $WPA_CLI_PIDFILE -i $WPA_IFACE"
 367
 368	wpa_msg verbose "$WPA_CLI_BIN $WPA_CLI_OPTIONS -p $WPA_CTRL_DIR -a $WPA_ACTION_SCRIPT"
 369		
 370	start-stop-daemon --start --oknodo $DAEMON_VERBOSITY \
 371		--name $WPA_CLI_PNAME --startas $WPA_CLI_BIN --pidfile $WPA_CLI_PIDFILE \
 372		-- $WPA_CLI_OPTIONS -p $WPA_CTRL_DIR -a $WPA_ACTION_SCRIPT
 373
 374	if [ "$?" -ne 0 ]; then
 375		wpa_msg stderr "$WPA_CLI_BIN daemon failed to start"
 376		return 1
 377	fi
 378
 379	if [ -n "$WPA_CLI_OMIT_PIDFILE" ]; then
 380		local WPA_PIDFILE_WAIT
 381		local MAX_WPA_PIDFILE_WAIT
 382		WPA_PIDFILE_WAIT="0"
 383		MAX_WPA_PIDFILE_WAIT="5"
 384		until [ -s "$WPA_CLI_PIDFILE" ]; do
 385			if [ "$WPA_PIDFILE_WAIT" -ge "$MAX_WPA_PIDFILE_WAIT" ]; then
 386				wpa_msg stderr "timed out waiting for creation of $WPA_CLI_PIDFILE"
 387				return 1
 388			else
 389				wpa_msg verbose "waiting for \"$WPA_CLI_PIDFILE\": " \
 390					"$WPA_PIDFILE_WAIT (max. $MAX_WPA_PIDFILE_WAIT)"
 391			fi
 392
 393			WPA_PIDFILE_WAIT=$(($WPA_PIDFILE_WAIT + 1))
 394			sleep 1
 395		done
 396		wpa_msg verbose "creating sendsigs omission pidfile: $WPA_CLI_OMIT_PIDFILE"
 397		cat "$WPA_CLI_PIDFILE" > "$WPA_CLI_OMIT_PIDFILE"
 398	else
 399		wpa_msg verbose "sendsigs omission pidfile not created"
 400	fi
 401}
 402
 403#####################################################################
 404## stop wpa_cli process
 405# Kill wpa_cli via start-stop-daemon, given the location of the
 406# pidfile
 407#
 408kill_wpa_cli () {
 409	test_wpa_cli || return 0
 410	
 411	wpa_msg verbose "terminating $WPA_CLI_PNAME daemon via pidfile $WPA_CLI_PIDFILE"
 412	
 413	start-stop-daemon --stop --oknodo $DAEMON_VERBOSITY \
 414		--exec $WPA_CLI_BIN --pidfile $WPA_CLI_PIDFILE
 415	
 416	if [ -f "$WPA_CLI_PIDFILE" ]; then
 417		rm -f "$WPA_CLI_PIDFILE"
 418	fi
 419
 420	if [ -f "$WPA_CLI_OMIT_PIDFILE" ]; then
 421		rm -f "$WPA_CLI_OMIT_PIDFILE"
 422	fi
 423
 424	if [ -f "$WPA_CLI_TIMESTAMP" ]; then
 425		rm -f "$WPA_CLI_TIMESTAMP"
 426	fi
 427
 428	if [ -L "$WPA_CLI_IFUPDOWN" ]; then
 429		rm -f "$WPA_CLI_IFUPDOWN"
 430	fi
 431}
 432
 433#####################################################################
 434## higher level wpa_cli wrapper for variable and set_network commands
 435# wpa_cli_do <value> <type> <variable> [set_network variable] <desc>
 436#
 437# $1	envorinment variable
 438# $2	data type of variable {raw|ascii}
 439# $3	wpa_cli variable, if $3 is set_network, shift and take 
 440#	set_network subvariable
 441# $4	wpa-* string as it would appear in interfaces file, enhances
 442#	verbose messages
 443#
 444wpa_cli_do () {
 445	if [ -z "$1" ]; then
 446		return 0
 447	fi
 448	
 449	local WPACLISET_VALUE
 450	local WPACLISET_VARIABLE
 451	local WPACLISET_DESC
 452	
 453	case "$2" in
 454		ascii)
 455			# Double quote
 456			WPACLISET_VALUE="\"$1\""
 457			;;
 458		raw|*)
 459			# Provide raw value
 460			WPACLISET_VALUE="$1"
 461			;;
 462	esac
 463	
 464	case "$3" in
 465		set_network)
 466			if [ -z "$WPA_ID" ]; then
 467				return 1
 468			fi
 469			shift
 470			WPACLISET_VARIABLE="set_network $WPA_ID $3"
 471			;;
 472		*)
 473			WPACLISET_VARIABLE="$3"
 474			;;
 475	esac
 476	
 477	case "$4" in
 478		*-psk|*-passphrase|*-passwd*|*-wep-key*)
 479			WPACLISET_DESC="$4 *****"
 480			;;
 481		*)
 482			WPACLISET_DESC="$4 $WPACLISET_VALUE"
 483			;;
 484	esac
 485
 486	wpa_msg action "$WPACLISET_DESC"
 487	
 488	wpa_cli $WPACLISET_VARIABLE "$WPACLISET_VALUE" >$TO_NULL
 489
 490	if [ "$?" -ne 0 ]; then
 491		wpa_msg stderr "$WPACLISET_DESC failed!"
 492	fi
 493}
 494
 495#####################################################################
 496## check value data type in plaintext or hex
 497# returns 0 if input consists of hexadecimal digits only, 1 otherwise
 498#
 499ishex () {
 500	if [ -z "$1" ]; then 
 501		return 0
 502	fi
 503	
 504	case "$1" in
 505		*[!0-9a-fA-F]*)
 506			# plaintext
 507			return 1
 508			;;
 509		*)
 510			# hexadecimal
 511			return 0
 512			;;
 513	esac
 514}
 515
 516#####################################################################
 517## sanity check and set psk|passphrase
 518# Warn about strange psk|passphrase values
 519#
 520# $1	psk or passphrase value
 521# 
 522# If psk is surrounded by quotes strip them.
 523#
 524# If psk contains all hexadecimal characters and string length is 64:
 525#	is 256bit hexadecimal
 526# else:
 527# 	is plaintext
 528#
 529# plaintext passphrases must be 8 - 63 characters in length
 530# 256-bit hexadecimal key must be 64 characters in length
 531#
 532wpa_key_check_and_set () {
 533	if [ "$#" -ne 3 ]; then
 534		return 0
 535	fi
 536
 537	local KEY
 538	local KEY_LEN
 539	local KEY_TYPE
 540	local ENC_TYPE
 541	
 542	case "$1" in
 543		'"'*'"')
 544			# Strip surrounding quotation marks
 545			KEY=$(echo -n "$1" | sed 's/^"//;s/"$//')
 546			;;
 547		*)
 548			KEY="$1"
 549			;;
 550	esac
 551
 552	KEY_LEN="${#KEY}"
 553
 554	case "$2" in
 555		wep_key*)
 556			ENC_TYPE="WEP"
 557			;;
 558		psk)
 559			ENC_TYPE="WPA"
 560			;;
 561		*)
 562			return 0
 563			;;
 564	esac
 565
 566	if [ "$ENC_TYPE" = "WEP" ]; then
 567		if ishex "$KEY"; then
 568			case "$KEY_LEN" in
 569				10|26|32|58)
 570					# 64/128/152/256-bit WEP
 571					KEY_TYPE="raw"
 572					;;
 573				*)
 574					KEY_TYPE="ascii"
 575					;;
 576			esac
 577		else
 578			KEY_TYPE="ascii"
 579		fi
 580
 581		if [ "$KEY_TYPE" = "ascii" ]; then
 582			if [ "$KEY_LEN" -lt "5" ]; then
 583				wpa_msg stderr "WARNING: plaintext or ascii WEP key has $KEY_LEN characters,"
 584				wpa_msg stderr "it must have at least 5 to be valid."
 585			fi
 586		fi
 587	elif [ "$ENC_TYPE" = "WPA" ]; then
 588		if ishex "$KEY"; then
 589			case "$KEY_LEN" in
 590				64)
 591					# 256-bit WPA
 592					KEY_TYPE="raw"
 593					;;
 594				*)
 595					KEY_TYPE="ascii"
 596					;;
 597			esac
 598		else
 599			KEY_TYPE="ascii"
 600		fi
 601
 602		if [ "$KEY_TYPE" = "ascii" ]; then
 603			if [ "$KEY_LEN" -lt "8" ] || [ "$KEY_LEN" -gt "63" ]; then
 604				wpa_msg stderr "WARNING: plaintext or ascii WPA key has $KEY_LEN characters,"
 605				wpa_msg stderr "it must have between 8 and 63 to be valid."
 606				wpa_msg stderr "If the WPA key is a 256-bit hexadecimal key, it must have"
 607				wpa_msg stderr "exactly 64 characters."
 608			fi
 609		fi
 610	fi
 611
 612	wpa_cli_do "$KEY" "$KEY_TYPE" set_network "$2" "$3"
 613}
 614
 615#####################################################################
 616## formulate a usable configuration from interfaces(5) wpa- lines
 617# A series of wpa_cli commands corresponding to environment variables
 618# created as a result of wpa- lines in an interfaces stanza.
 619#
 620# NB: no-act when roaming daemon is used (to avoid prematurely
 621# attaching to ctrl_interface socket)
 622#
 623conf_wpa_supplicant () {
 624	if [ -n "$WPA_ACTION_SCRIPT" ]; then
 625		return 0
 626	fi
 627
 628	if [ "$IF_WPA_DRIVER" = "wired" ]; then
 629		IF_WPA_AP_SCAN="0"
 630		wpa_msg verbose "forcing ap_scan=0 (required for wired IEEE8021X auth)"
 631	fi
 632
 633	if [ -n "$IF_WPA_ESSID" ]; then
 634		# #403316, be similar to wireless tools
 635		IF_WPA_SSID="$IF_WPA_ESSID"
 636	fi
 637	
 638	wpa_cli_do "$IF_WPA_AP_SCAN" raw \
 639		ap_scan wpa-ap-scan
 640	
 641	wpa_cli_do "$IF_WPA_PREAUTHENTICATE" raw \
 642		preauthenticate wpa-preauthenticate
 643		
 644	if [ -n "$IF_WPA_SSID" ] || [ "$IF_WPA_DRIVER" = "wired" ] || \
 645		[ -n "$IF_WPA_KEY_MGMT" ]; then
 646		
 647		case "$IF_WPA_SSID" in
 648			'"'*'"')
 649				IF_WPA_SSID=$(echo -n "$IF_WPA_SSID" | sed 's/^"//;s/"$//')
 650				;;
 651			*)
 652				;;
 653		esac
 654		
 655		WPA_ID=$(wpa_cli add_network)
 656
 657		wpa_msg verbose "configuring network block -- $WPA_ID"
 658		
 659		wpa_cli_do "$IF_WPA_SSID" ascii \
 660			set_network ssid wpa-ssid
 661		
 662		wpa_cli_do "$IF_WPA_PRIORITY" raw \
 663			set_network priority wpa-priority
 664		
 665		wpa_cli_do "$IF_WPA_BSSID" raw \
 666			set_network bssid wpa-bssid
 667		
 668		if [ -s "$IF_WPA_PSK_FILE" ]; then
 669			IF_WPA_PSK=$(cat "$IF_WPA_PSK_FILE")
 670		fi
 671		
 672		# remain compat with wpa-passphrase-file
 673		if [ -s "$IF_WPA_PASSPHRASE_FILE" ]; then
 674			IF_WPA_PSK=$(cat "$IF_WPA_PASSPHRASE_FILE")
 675		fi
 676		
 677		# remain compat with wpa-passphrase
 678		if [ -n "$IF_WPA_PASSPHRASE" ]; then
 679			IF_WPA_PSK="$IF_WPA_PASSPHRASE"
 680		fi
 681	
 682		if [ -n "$IF_WPA_PSK" ]; then
 683			wpa_key_check_and_set "$IF_WPA_PSK" \
 684				psk wpa-psk
 685		fi
 686		
 687		wpa_cli_do "$IF_WPA_PAIRWISE" raw \
 688			set_network pairwise wpa-pairwise
 689		
 690		wpa_cli_do "$IF_WPA_GROUP" raw \
 691			set_network group wpa-group
 692
 693		wpa_cli_do "$IF_WPA_MODE" raw \
 694			set_network mode wpa-mode
 695
 696		wpa_cli_do "$IF_WPA_FREQUENCY" raw \
 697			set_network frequency wpa-frequency
 698		
 699		wpa_cli_do "$IF_WPA_KEY_MGMT" raw \
 700			set_network key_mgmt wpa-key-mgmt
 701		
 702		wpa_cli_do "$IF_WPA_PROTO" raw \
 703			set_network proto wpa-proto
 704		
 705		wpa_cli_do "$IF_WPA_AUTH_ALG" raw \
 706			set_network auth_alg wpa-auth-alg
 707		
 708		wpa_cli_do "$IF_WPA_SCAN_SSID" raw \
 709			set_network scan_ssid wpa-scan-ssid
 710		
 711		wpa_cli_do "$IF_WPA_IDENTITY" ascii \
 712			set_network identity wpa-identity
 713		
 714		wpa_cli_do "$IF_WPA_ANONYMOUS_IDENTITY" ascii \
 715			set_network anonymous_identity wpa-anonymous-identity
 716		
 717		wpa_cli_do "$IF_WPA_EAP" raw \
 718			set_network eap wpa-eap
 719		
 720		wpa_cli_do "$IF_WPA_EAPPSK" raw \
 721			set_network eappsk wpa-eappsk
 722
 723		wpa_cli_do "$IF_WPA_NAI" ascii \
 724			set_network nai wpa-nai
 725
 726		wpa_cli_do "$IF_WPA_PASSWORD" ascii \
 727			set_network password wpa-password
 728
 729		wpa_cli_do "$IF_WPA_CA_CERT" ascii \
 730			set_network ca_cert wpa-ca-cert
 731
 732		wpa_cli_do "$IF_WPA_CA_PATH" ascii \
 733			set_network ca_path wpa-ca-path
 734
 735		wpa_cli_do "$IF_WPA_CLIENT_CERT" ascii \
 736			set_network client_cert wpa-client-cert
 737
 738		wpa_cli_do "$IF_WPA_PRIVATE_KEY" ascii \
 739			set_network private_key wpa-private-key
 740
 741		wpa_cli_do "$IF_WPA_PRIVATE_KEY_PASSWD" ascii \
 742			set_network private_key_passwd wpa-private-key-passwd
 743		
 744		wpa_cli_do "$IF_WPA_DH_FILE" ascii \
 745			set_network dh_file wpa-dh-file
 746
 747		wpa_cli_do "$IF_WPA_SUBJECT_MATCH" ascii \
 748			set_network subject_match wpa-subject-match
 749
 750		wpa_cli_do "$IF_WPA_ALTSUBJECT_MATCH" ascii \
 751			set_network altsubject_match wpa-altsubject-match
 752
 753		wpa_cli_do "$IF_WPA_CA_CERT2" ascii \
 754			set_network ca_cert2 wpa-ca-cert2
 755
 756		wpa_cli_do "$IF_WPA_CA_PATH2" ascii \
 757			set_network ca_path2 wpa-ca-path2
 758
 759		wpa_cli_do "$IF_WPA_CLIENT_CERT2" ascii \
 760			set_network client_cert2 wpa-client-cert2
 761
 762		wpa_cli_do "$IF_WPA_PRIVATE_KEY2" ascii \
 763			set_network private_key2 wpa-private-key2
 764
 765		wpa_cli_do "$IF_WPA_PRIVATE_KEY_PASSWD2" ascii \
 766			set_network private_key_passwd2 wpa-private-key-passwd2
 767		
 768		wpa_cli_do "$IF_WPA_DH_FILE2" ascii \
 769			set_network dh_file2 wpa-dh-file2
 770
 771		wpa_cli_do "$IF_WPA_SUBJECT_MATCH2" ascii \
 772			set_network subject_match2 wpa-subject-match2
 773
 774		wpa_cli_do "$IF_WPA_ALTSUBJECT_MATCH2" ascii \
 775			set_network altsubject_match2 wpa-altsubject-match2
 776		
 777		wpa_cli_do "$IF_WPA_EAP_METHODS" raw \
 778			set_network eap_methods wpa-eap-methods
 779
 780		wpa_cli_do "$IF_WPA_PHASE1" ascii \
 781			set_network phase1 wpa-phase1
 782
 783		wpa_cli_do "$IF_WPA_PHASE2" ascii \
 784			set_network phase2 wpa-phase2
 785
 786		wpa_cli_do "$IF_WPA_PCSC" raw \
 787			set_network pcsc wpa-pcsc
 788
 789		wpa_cli_do "$IF_WPA_PIN" ascii \
 790			set_network pin wpa-pin
 791
 792		wpa_cli_do "$IF_WPA_ENGINE" raw \
 793			set_network engine wpa-engine
 794
 795		wpa_cli_do "$IF_WPA_ENGINE_ID" ascii \
 796			set_network engine_id wpa-engine-id
 797
 798		wpa_cli_do "$IF_WPA_KEY_ID" ascii \
 799			set_network key_id wpa-key-id
 800
 801		wpa_cli_do "$IF_WPA_EAPOL_FLAGS" raw \
 802			set_network eapol_flags wpa-eapol-flags
 803		
 804		if [ -n "$IF_WPA_WEP_KEY0" ]; then
 805			wpa_key_check_and_set "$IF_WPA_WEP_KEY0" \
 806				wep_key0 wpa-wep-key0
 807		fi
 808		
 809		if [ -n "$IF_WPA_WEP_KEY1" ]; then
 810			wpa_key_check_and_set "$IF_WPA_WEP_KEY1" \
 811				wep_key1 wpa-wep-key1
 812		fi
 813
 814		if [ -n "$IF_WPA_WEP_KEY2" ]; then
 815			wpa_key_check_and_set "$IF_WPA_WEP_KEY2" \
 816				wep_key2 wpa-wep-key2
 817		fi
 818
 819		if [ -n "$IF_WPA_WEP_KEY3" ]; then
 820			wpa_key_check_and_set "$IF_WPA_WEP_KEY3" \
 821				wep_key3 wpa-wep-key3
 822		fi
 823		
 824		wpa_cli_do "$IF_WPA_WEP_TX_KEYIDX" raw \
 825			set_network wep_tx_keyidx wpa-wep-tx-keyidx
 826		
 827		wpa_cli_do "$IF_WPA_PROACTIVE_KEY_CACHING" raw \
 828			set_network proactive_key_caching wpa-proactive-key-caching
 829			
 830		wpa_cli_do "$IF_WPA_PAC_FILE" ascii \
 831			set_network pac_file wpa-pac-file
 832		
 833		wpa_cli_do "$IF_WPA_MODE" raw \
 834			set_network mode wpa-mode
 835		
 836		wpa_cli_do "$IF_WPA_PEERKEY" raw \
 837			set_network peerkey wpa-peerkey
 838			
 839		wpa_cli_do "$IF_FRAGMENT_SIZE" raw \
 840			set_network fragment_size wpa-fragment-size
 841
 842		wpa_cli_do "$IF_WPA_ID_STR" ascii \
 843			set_network id_str wpa-id-str
 844		
 845		wpa_cli_do "$WPA_ID" raw \
 846			enable_network "enabling network block"
 847	fi
 848}
 849
 850#####################################################################
 851## wpa_action basic logging
 852# Log actions to file
 853#
 854wpa_log_init () {
 855	if touch "$WPA_CLI_LOGFILE" 2>/dev/null; then
 856		exec >> "$WPA_CLI_LOGFILE" 2>&1
 857	fi
 858}
 859
 860# log timestamp and wpa_action arguments
 861wpa_log_action () {
 862	[ -w "$WPA_CLI_LOGFILE" ] || return 0
 863	
 864	local DATE
 865	DATE=$(date +"%H:%M:%S  %Y-%m-%d")
 866	
 867	echo "########## $DATE ##########"
 868	echo "IFACE=$WPA_IFACE ACTION=$WPA_ACTION"
 869}
 870
 871# log wpa_cli environment variables
 872wpa_log_environment () {
 873	[ -w "$WPA_CLI_LOGFILE" ] || return 0
 874
 875	echo "WPA_ID=$WPA_ID WPA_ID_STR=$WPA_ID_STR"
 876	echo "WPA_CTRL_DIR=$WPA_CTRL_DIR"
 877}
 878
 879#####################################################################
 880## hysteresis checking
 881# Networking tools such as dhcp clients used with ifupdown can
 882# synthesize artificial ACTION events, particuarly just after a
 883# DISCONNECTED/CONNECTED events are experienced in quick succession.
 884# This can lead to infinite event loops, and in extreme cases has the
 885# potential to cause system instability.
 886#
 887wpa_hysteresis_event () {
 888	local TIME
 889
 890	TIME=$(date +%s)
 891	echo "$TIME" > "$WPA_CLI_TIMESTAMP"
 892}
 893
 894wpa_hysteresis_check () {
 895	if [ -f "$WPA_CLI_TIMESTAMP" ]; then
 896		local TIME
 897		local TIMESTAMP
 898		local TIMEWAIT
 899		TIME=$(date +%s)
 900		# current time minus 4 second event buffer
 901		TIMEWAIT=$(($TIME-4))
 902		# get time of last event
 903		TIMESTAMP=$(cat $WPA_CLI_TIMESTAMP)
 904		# compare values, allowing new action to be processed 
 905		# only if last action was more than 4 seconds ago
 906		if [ "$TIMEWAIT" -le "$TIMESTAMP" ]; then
 907			echo "Ignoring $WPA_ACTION event, too soon after previous event"
 908			return 1
 909		fi
 910	fi
 911
 912	return 0
 913}
 914
 915#####################################################################
 916## identify ifupdown files
 917# Identify ifupdown core files, so that state of the interface can be
 918# checked. This is the weakest part of the wpa_action roaming scheme,
 919# it would be _much_ better if stateless ifupdown capabilities were
 920# a reality.
 921#
 922ifupdown_check () {
 923	if [ -e /etc/network/interfaces ]; then
 924		INTERFACES_FILE="/etc/network/interfaces"
 925	else
 926		echo "Cannot locate ifupdown's \"interfaces\" file, $WPA_IFACE will not be configured"
 927		return 1
 928	fi
 929
 930	if [ -e /etc/network/run/ifstate ]; then
 931		# debian's ifupdown
 932		IFSTATE_FILE="/etc/network/run/ifstate"
 933	elif [ -e /var/run/network/ifstate ]; then
 934		# ubuntu's
 935		IFSTATE_FILE="/var/run/network/ifstate"
 936	else
 937		echo "Cannot locate ifupdown's \"ifstate\" file, $WPA_IFACE will not be configured"
 938		return 1
 939	fi
 940
 941	return 0
 942}
 943
 944ifupdown_status () {
 945	if grep -s -q "^${WPA_IFACE}=${WPA_LOGICAL_IFACE}" "$IFSTATE_FILE"; then
 946		return 0
 947	fi
 948
 949	echo "Interface \"$WPA_IFACE\" failed to establish a connection."
 950	echo "Attempting reassociation..."
 951	return 1
 952}
 953
 954ifupdown_lock () {
 955	ln -s lock "$WPA_CLI_IFUPDOWN"
 956}
 957
 958ifupdown_locked () {
 959	[ -L "$WPA_CLI_IFUPDOWN" ] && return 0
 960
 961	return 1
 962}
 963
 964ifupdown_unlock () {
 965	rm -f "$WPA_CLI_IFUPDOWN"
 966}
 967
 968#####################################################################
 969## apply mapping logic and ifup logical interface
 970# Apply mapping logic via id_str or external mapping script, check
 971# state of IFACE with respect to ifupdown and ifup logical interaface
 972#
 973ifup () {
 974	local WPA_LOGICAL_IFACE
 975	
 976	if [ -z "$IF_WPA_MAPPING_SCRIPT_PRIORITY" ] && [ -n "$WPA_ID_STR" ]; then
 977		WPA_LOGICAL_IFACE="$WPA_ID_STR"
 978		echo "Mapping logical interface via id_str: $WPA_LOGICAL_IFACE"
 979	fi
 980	
 981	if [ -z "$WPA_LOGICAL_IFACE" ] && [ -n "$IF_WPA_MAPPING_SCRIPT" ]; then
 982		echo "Mapping logical interface via wpa-mapping-script: $IF_WPA_MAPPING_SCRIPT"
 983		
 984		local WPA_MAP_STDIN
 985		
 986		WPA_MAP_STDIN=$(set | sed -n 's/^\(IF_WPA_MAP[0-9]*\)=.*/echo \$\1/p')
 987		
 988		if [ -n "$WPA_MAP_STDIN" ]; then
 989			WPA_LOGICAL_IFACE=$(eval "$WPA_MAP_STDIN" | "$IF_WPA_MAPPING_SCRIPT" "$WPA_IFACE")
 990		else		
 991			WPA_LOGICAL_IFACE=$("$IF_WPA_MAPPING_SCRIPT" "$WPA_IFACE")
 992		fi
 993		
 994		if [ -n "$WPA_LOGICAL_IFACE" ]; then
 995			echo "Mapping script result: $WPA_LOGICAL_IFACE"
 996		else
 997			echo "Mapping script failed."
 998		fi
 999	fi
1000
1001	if [ -z "$WPA_LOGICAL_IFACE" ]; then
1002		if [ -n "$IF_WPA_ROAM_DEFAULT_IFACE" ]; then
1003			WPA_LOGICAL_IFACE="$IF_WPA_ROAM_DEFAULT_IFACE"
1004			echo "Using wpa-roam-default-iface: $WPA_LOGICAL_IFACE"
1005		else
1006			WPA_LOGICAL_IFACE="default"
1007			echo "Using fallback logical interface: $WPA_LOGICAL_IFACE"
1008		fi
1009	fi
1010
1011	if [ -n "$WPA_LOGICAL_IFACE" ]; then
1012		if egrep -q "^iface[[:space:]]+${WPA_LOGICAL_IFACE}[[:space:]]+inet" "$INTERFACES_FILE"; then
1013			: # logical network is defined
1014		else
1015			echo "No network defined for \"$WPA_LOGICAL_IFACE\" in \"$INTERFACES_FILE\""
1016			echo "Trying to configure the \"default\" network instead ..."
1017			WPA_LOGICAL_IFACE="default"
1018		fi
1019			
1020		echo "ifup $WPA_IFACE=$WPA_LOGICAL_IFACE"
1021
1022		ifupdown_lock
1023		
1024		if grep -q "^$WPA_IFACE=$WPA_IFACE" "$IFSTATE_FILE"; then
1025			# Force settings over the unconfigured "master" IFACE
1026			/sbin/ifup -v --force "$WPA_IFACE=$WPA_LOGICAL_IFACE"
1027		else
1028			/sbin/ifup -v "$WPA_IFACE=$WPA_LOGICAL_IFACE"
1029		fi
1030
1031		ifupdown_unlock
1032	else
1033		echo "No suitable logical interface mapping for ifupdown to configure"
1034	fi
1035}
1036
1037#####################################################################
1038## ifdown IFACE
1039# Check IFACE state and ifdown as requested.
1040#
1041ifdown () {
1042	if grep -q "^$WPA_IFACE" "$IFSTATE_FILE"; then
1043		ifupdown_lock
1044
1045		echo "ifdown $WPA_IFACE"
1046		/sbin/ifdown -v "$WPA_IFACE"
1047
1048		ifupdown_unlock
1049	else
1050		echo "Ignoring request to take \"$WPA_IFACE\" down, it is not up"
1051	fi
1052}
1053
1054#####################################################################
1055## keep IFACE scanning
1056# After ifdown, the IFACE may be left "down", and inhibits 
1057# wpa_supplicant's ability to continue roaming.
1058#
1059# NB: use iproute if present, flushing the IFACE first
1060#
1061if_post_down_up () {
1062	if type ip >/dev/null; then
1063		ip addr flush dev "$WPA_IFACE" 2>/dev/null
1064		ip link set "$WPA_IFACE" up
1065	else
1066		ifconfig "$WPA_IFACE" up
1067	fi
1068}