#!/bin/bash ############################################################################### # # # IPFire.org - A linux based firewall # # Copyright (C) 2017 IPFire Network Development Team # # # # This program is free software: you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # # the Free Software Foundation, either version 3 of the License, or # # (at your option) any later version. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with this program. If not, see . # # # ############################################################################### WIRELESS_NETWORK_SUPPORTED_PSK_MODES="WPA2-PSK-SHA256 WPA2-PSK WPA-PSK-SHA256 WPA-PSK" WIRELESS_NETWORK_SUPPORTED_MODES="${WIRELESS_NETWORK_SUPPORTED_PSK_MODES} NONE" WIRELESS_NETWORK_CONFIG_SETTINGS="EAP_MODES ENCRYPTION_MODES PRIORITY PSK SSID" cli_wireless_network() { case "${1}" in new) wireless_network_new "${@:2}" ;; destroy) wireless_network_destroy "${@:2}" ;; *) local ssid="${1}" local key="${2//-/_}" shift 2 if ! wireless_network_exists "${ssid}"; then error "No such wireless network: ${ssid}" return ${EXIT_ERROR} fi # Convert SSID into usable format local handle="$(wireless_network_hash "${ssid}")" case "${key}" in encryption_mode|pre_shared_key|priority) wireless_network_${key} "${handle}" "$@" ;; show) wireless_network_show "${handle}" exit $? ;; *) error "Unrecognized argument: ${key}" exit ${EXIT_ERROR} ;; esac ;; esac } wireless_network_list() { list_directory "${NETWORK_WIRELESS_NETWORKS_DIR}" } wireless_network_list_ssids() { local handle for handle in $(wireless_network_list); do local ${WIRELESS_NETWORK_CONFIG_SETTINGS} if ! wireless_network_read_config "${handle}"; then continue fi print "${SSID}" done } # This function writes all values to a via ${ssid} specificated wireless network configuration file wireless_network_write_config() { assert [ $# -ge 1 ] local handle="${1}" local path="${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}/settings" if ! settings_write "${path}" ${WIRELESS_NETWORK_CONFIG_SETTINGS}; then log ERROR "Could not write configuration" return ${EXIT_ERROR} fi # When we get here the writing of the config file was successful return ${EXIT_OK} } # This funtion writes the value for one key to a via ${ssid} specificated # wireless network configuration file wireless_network_write_config_key() { assert [ $# -ge 3 ] local handle="${1}" local key="${2}" shift 2 local value="$@" local ${WIRELESS_NETWORK_CONFIG_SETTINGS} # Read the config settings if ! wireless_network_read_config "${handle}"; then return ${EXIT_ERROR} fi log DEBUG "Set '${key}' to new value '${value}' in wireless network '${SSID}'" # Set the key to a new value assign "${key}" "${value}" if ! wireless_network_write_config "${handle}"; then return ${EXIT_ERROR} fi return ${EXIT_OK} } # Reads one or more keys out of a settings file or all if no key is provided. wireless_network_read_config() { assert [ $# -ge 1 ] local handle="${1}" shift local args if [ $# -eq 0 ] && [ -n "${WIRELESS_NETWORK_CONFIG_SETTINGS}" ]; then list_append args ${WIRELESS_NETWORK_CONFIG_SETTINGS} else list_append args "$@" fi local path="${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}/settings" if ! settings_read "${path}" ${args}; then log ERROR "Could not read settings for wireless network ${handle}" return ${EXIT_ERROR} fi } # This function checks if a wireless network exists # Returns True when yes and false when not wireless_network_exists() { local ssid="${1}" local handle="$(wireless_network_hash "${ssid}")" assert isset handle # We cannot use wireless_network_read_config here beacuse we would end in a loop local SSID if ! settings_read "${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}/settings" SSID; then return ${EXIT_FALSE} fi if [ "${SSID}" = "${ssid}" ]; then return ${EXIT_TRUE} else return ${EXIT_FALSE} fi } wireless_network_hash() { assert [ $# -eq 1 ] local string="${1}" local hash=$(echo -n "${string}" | md5sum ) hash=${hash%% -} local path="${NETWORK_WIRELESS_NETWORKS_DIR}/*${hash}" if [ -d "${path}" ]; then basename "${path}" else local normalized=$(normalize "${string}") normalized=${normalized%-} echo "${normalized}-${hash}" fi } wireless_network_new() { if [ $# -gt 1 ]; then error "Too many arguments" return ${EXIT_ERROR} fi local ssid="${1}" if ! isset ssid; then error "Please provide a SSID" return ${EXIT_ERROR} fi # Check for duplicates if wireless_network_exists "${ssid}"; then error "The wireless network ${ssid} already exists" return ${EXIT_ERROR} fi local handle="$(wireless_network_hash "${ssid}")" assert isset handle log DEBUG "Creating wireless network '${ssid}'" if ! mkdir -p "${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}"; then log ERROR "Could not create config directory for wireless network ${ssid}" return ${EXIT_ERROR} fi local ${WIRELESS_NETWORK_CONFIG_SETTINGS} ENCRYPTION_MODE="${WIRELESS_DEFAULT_ENCRYPTION_MODE}" SSID="${ssid}" PRIORITY=500 if ! wireless_network_write_config "${handle}"; then log ERROR "Could not write new config file" return ${EXIT_ERROR} fi } # Deletes a wireless network wireless_network_destroy() { local ssid="${1}" if ! wireless_network_exists "${ssid}"; then error "No such wireless network: ${ssid}" return ${EXIT_ERROR} fi local handle="$(wireless_network_hash "${ssid}")" assert isset handle if ! rm -rf "${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}"; then error "Could not delete the wireless network" return ${EXIT_ERROR} fi log INFO "Successfully destroyed wireless network ${ssid}" return ${EXIT_OK} } wireless_network_encryption_mode() { if [ ! $# -eq 2 ]; then log ERROR "Not enough arguments" return ${EXIT_ERROR} fi local handle="${1}" local mode="${2}" if ! isoneof mode ${WIRELESS_VALID_ENCRYPTION_MODES}; then log ERROR "Encryption mode '${mode}' is invalid" return ${EXIT_ERROR} fi local ${WIRELESS_NETWORK_CONFIG_SETTINGS} if ! wireless_network_read_config "${handle}"; then error "Could not read configuration" return ${EXIT_ERROR} fi # Validate the PSK when changing mode and reset if needed if isset PSK && [ "${mode}" != "NONE" ] && \ ! wireless_pre_shared_key_is_valid "${mode}" "${PSK}"; then log WARNING "The configured pre-shared-key is incompatible with this encryption mode and has been reset" PSK="" fi # Save new encryption mode ENCRYPTION_MODE="${mode}" if ! wireless_network_write_config "${handle}"; then log ERROR "Could not write configuration settings" return ${EXIT_ERROR} fi } wireless_network_pre_shared_key() { if [ ! $# -eq 2 ]; then log ERROR "Not enough arguments" return ${EXIT_ERROR} fi local handle="${1}" local psk="${2}" local ${WIRELESS_NETWORK_CONFIG_SETTINGS} if ! wireless_network_read_config "${handle}"; then error "Could not read configuration" return ${EXIT_ERROR} fi # Validate the key if encryption mode is known if isset ENCRYPTION_MODE && [ "${ENCRYPTION_MODE}" != "NONE" ]; then if ! wireless_pre_share_key_is_valid "${ENCRYPTION_MODE}" "${psk}"; then error "The pre-shared-key is invalid for this wireless network: ${psk}" return ${EXIT_ERROR} fi fi if ! wireless_network_write_config_key "${handle}" "PSK" "${psk}"; then log ERROR "Could not write configuration settings" return ${EXIT_ERROR} fi } wireless_network_priority() { if [ ! $# -eq 2 ]; then log ERROR "Not enough arguments" return ${EXIT_ERROR} fi local handle="${1}" local priority=${2} if ! isinteger priority && [ ! ${priority} -ge 0 ]; then log ERROR "The priority must be an integer greater or eqal zero" return ${EXIT_ERROR} fi if ! wireless_network_write_config_key "${handle}" "PRIORITY" "${priority}"; then log ERROR "Could not write configuration settings" return ${EXIT_ERROR} fi } wireless_networks_write_wpa_supplicant_configuration() { local device="${1}" local file="${WPA_SUPPLICANT_CONF_DIR}/${device}.conf" # Ensure we can write the file make_parent_directory "${file}" local country="$(wireless_get_reg_domain)" ( config_header "WPA supplicant configuration file" # Set control socket directory. print "ctrl_interface=${WPA_SUPPLICANT_SOCKET_DIR}" # Honour country if isset country; then print "country=${country}" print fi wireless_networks_to_wpa_supplicant ) > ${file} } wireless_networks_to_wpa_supplicant() { local handle for handle in $(wireless_network_list); do wireless_network_to_wpa_supplicant "${handle}" done } wireless_network_to_wpa_supplicant() { local handle="${1}" local ${WIRELESS_NETWORK_CONFIG_SETTINGS} if ! wireless_network_read_config "${handle}"; then error "Could not read configuration for ${handle}" return ${EXIT_ERROR} fi local auth_alg local group local key_mgmt local pairwise local proto local mode for mode in ${WIRELESS_NETWORK_SUPPORTED_MODES}; do # Skip any disabled modes if isset ENCRYPTION_MODES && ! list_match "${mode}" ${ENCRYPTION_MODES}; then continue fi case "${mode}" in # WPA2 (802.11i) WPA2-PSK|WPA2-PSK-SHA256) list_append_unique auth_alg "OPEN" list_append_unique key_mgmt "${mode/WPA2/WPA}" list_append_unique proto "RSN" local p for p in CCMP TKIP; do list_append_unique pairwise "${p}" done local g for g in CCMP TKIP WEP104 WEP40; do list_append_unique group "${g}" done ;; # WPA WPA-PSK|WPA-PSK-SHA256) list_append_unique auth_alg "OPEN" list_append_unique key_mgmt "${mode}" list_append_unique proto "WPA" local p for p in CCMP TKIP; do list_append_unique pairwise "${p}" done local g for g in CCMP TKIP WEP104 WEP40; do list_append_unique group "${g}" done ;; # No encryption. DANGEROUS! NONE) list_append_unique auth_alg "OPEN" list_append_unique key_mgmt "NONE" ;; esac done assert isset auth_alg assert isset key_mgmt print_indent 0 "# ${SSID}" print_indent 0 "network={" print_indent 1 "ssid=\"${SSID}\"" # Priority if isinteger PRIORITY; then print_indent 1 "priority=${PRIORITY}" fi print # Authentication print_indent 1 "# Authentication" print_indent 1 "auth_alg=${auth_alg}" print_indent 1 "key_mgmt=${key_mgmt}" local i for i in proto pairwise group; do print_indent 1 "${i}=${!i}" done print # PSK if isset PSK; then print_indent 1 "# Pre Shared Key" print_indent 1 "psk=\"${PSK}\"" fi if isset EAP_MODES; then print_indent 1 "# EAP" print_indent 1 "eap=${EAP_MODES}" print fi print_indent 0 "}" print }