wpa_supplicant: Doesn't like spaces here
[people/stevee/network.git] / src / functions / functions.wireless-networks
CommitLineData
49958b8c
MT
1#!/bin/bash
2###############################################################################
3# #
4# IPFire.org - A linux based firewall #
5# Copyright (C) 2017 IPFire Network Development Team #
6# #
7# This program is free software: you can redistribute it and/or modify #
8# it under the terms of the GNU General Public License as published by #
9# the Free Software Foundation, either version 3 of the License, or #
10# (at your option) any later version. #
11# #
12# This program is distributed in the hope that it will be useful, #
13# but WITHOUT ANY WARRANTY; without even the implied warranty of #
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15# GNU General Public License for more details. #
16# #
17# You should have received a copy of the GNU General Public License #
18# along with this program. If not, see <http://www.gnu.org/licenses/>. #
19# #
20###############################################################################
21
790ab927
MT
22WIRELESS_NETWORK_SUPPORTED_PSK_MODES="WPA2-PSK-SHA256 WPA2-PSK WPA-PSK-SHA256 WPA-PSK"
23
24WIRELESS_NETWORK_SUPPORTED_MODES="${WIRELESS_NETWORK_SUPPORTED_PSK_MODES} NONE"
25
26WIRELESS_NETWORK_CONFIG_SETTINGS="EAP_MODES ENCRYPTION_MODES PRIORITY PSK SSID"
49958b8c 27
49958b8c 28cli_wireless_network() {
479b2273
MT
29 case "${1}" in
30 new)
31 wireless_network_new "${@:2}"
32 ;;
33 destroy)
34 wireless_network_destroy "${@:2}"
35 ;;
36 *)
37 local ssid="${1}"
38 local key="${2//-/_}"
549c5b97 39 shift 2
49958b8c 40
479b2273
MT
41 if ! wireless_network_exists "${ssid}"; then
42 error "No such wireless network: ${ssid}"
43 return ${EXIT_ERROR}
44 fi
49958b8c 45
2f64ac44
MT
46 # Convert SSID into usable format
47 local handle="$(wireless_network_hash "${ssid}")"
48
479b2273 49 case "${key}" in
364da6f4 50 encryption_mode|pre_shared_key|priority)
2f64ac44 51 wireless_network_${key} "${handle}" "$@"
479b2273
MT
52 ;;
53 show)
2f64ac44 54 wireless_network_show "${handle}"
479b2273
MT
55 exit $?
56 ;;
57 *)
58 error "Unrecognized argument: ${key}"
59 exit ${EXIT_ERROR}
60 ;;
61 esac
62 ;;
63 esac
49958b8c
MT
64}
65
d86b2dee
MT
66wireless_network_list() {
67 list_directory "${NETWORK_WIRELESS_NETWORKS_DIR}"
68}
69
70wireless_network_list_ssids() {
71 local handle
72 for handle in $(wireless_network_list); do
73 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
2f64ac44 74 if ! wireless_network_read_config "${handle}"; then
d86b2dee
MT
75 continue
76 fi
77
78 print "${SSID}"
79 done
80}
81
49958b8c
MT
82# This function writes all values to a via ${ssid} specificated wireless network configuration file
83wireless_network_write_config() {
84 assert [ $# -ge 1 ]
85
2f64ac44 86 local handle="${1}"
49958b8c 87
2f64ac44 88 local path="${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}/settings"
49958b8c
MT
89
90 if ! settings_write "${path}" ${WIRELESS_NETWORK_CONFIG_SETTINGS}; then
2f64ac44 91 log ERROR "Could not write configuration"
49958b8c
MT
92 return ${EXIT_ERROR}
93 fi
94
95 # When we get here the writing of the config file was successful
96 return ${EXIT_OK}
97}
98
99# This funtion writes the value for one key to a via ${ssid} specificated
100# wireless network configuration file
101wireless_network_write_config_key() {
102 assert [ $# -ge 3 ]
103
2f64ac44 104 local handle="${1}"
49958b8c
MT
105 local key="${2}"
106 shift 2
107
108 local value="$@"
109
49958b8c
MT
110 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
111
112 # Read the config settings
2f64ac44 113 if ! wireless_network_read_config "${handle}"; then
49958b8c
MT
114 return ${EXIT_ERROR}
115 fi
116
2f64ac44
MT
117 log DEBUG "Set '${key}' to new value '${value}' in wireless network '${SSID}'"
118
49958b8c
MT
119 # Set the key to a new value
120 assign "${key}" "${value}"
121
2f64ac44 122 if ! wireless_network_write_config "${handle}"; then
49958b8c
MT
123 return ${EXIT_ERROR}
124 fi
125
126 return ${EXIT_OK}
127}
128
d86b2dee 129# Reads one or more keys out of a settings file or all if no key is provided.
2f64ac44 130wireless_network_read_config() {
d86b2dee
MT
131 assert [ $# -ge 1 ]
132
133 local handle="${1}"
134 shift
135
49958b8c
MT
136 local args
137 if [ $# -eq 0 ] && [ -n "${WIRELESS_NETWORK_CONFIG_SETTINGS}" ]; then
138 list_append args ${WIRELESS_NETWORK_CONFIG_SETTINGS}
139 else
140 list_append args "$@"
141 fi
142
d86b2dee 143 local path="${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}/settings"
49958b8c
MT
144
145 if ! settings_read "${path}" ${args}; then
d86b2dee 146 log ERROR "Could not read settings for wireless network ${handle}"
49958b8c
MT
147 return ${EXIT_ERROR}
148 fi
149}
150
151# This function checks if a wireless network exists
152# Returns True when yes and false when not
153wireless_network_exists() {
49958b8c 154 local ssid="${1}"
49958b8c 155
2f64ac44
MT
156 local handle="$(wireless_network_hash "${ssid}")"
157 assert isset handle
49958b8c
MT
158
159 # We cannot use wireless_network_read_config here beacuse we would end in a loop
160 local SSID
2f64ac44 161 if ! settings_read "${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}/settings" SSID; then
49958b8c
MT
162 return ${EXIT_FALSE}
163 fi
164
2f64ac44 165 if [ "${SSID}" = "${ssid}" ]; then
49958b8c
MT
166 return ${EXIT_TRUE}
167 else
168 return ${EXIT_FALSE}
169 fi
170}
171
172wireless_network_hash() {
173 assert [ $# -eq 1 ]
174
175 local string="${1}"
176
177 local hash=$(echo -n "${string}" | md5sum )
178 hash=${hash%% -}
179
180 local path="${NETWORK_WIRELESS_NETWORKS_DIR}/*${hash}"
181
182 if [ -d "${path}" ]; then
183 basename "${path}"
184 else
185 local normalized=$(normalize "${string}")
186 normalized=${normalized%-}
187 echo "${normalized}-${hash}"
188 fi
189}
190
191wireless_network_new() {
192 if [ $# -gt 1 ]; then
193 error "Too many arguments"
194 return ${EXIT_ERROR}
195 fi
196
197 local ssid="${1}"
2f64ac44 198
49958b8c
MT
199 if ! isset ssid; then
200 error "Please provide a SSID"
201 return ${EXIT_ERROR}
202 fi
203
49958b8c
MT
204 # Check for duplicates
205 if wireless_network_exists "${ssid}"; then
206 error "The wireless network ${ssid} already exists"
207 return ${EXIT_ERROR}
208 fi
209
2f64ac44
MT
210 local handle="$(wireless_network_hash "${ssid}")"
211 assert isset handle
212
49958b8c
MT
213 log DEBUG "Creating wireless network '${ssid}'"
214
2f64ac44 215 if ! mkdir -p "${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}"; then
49958b8c
MT
216 log ERROR "Could not create config directory for wireless network ${ssid}"
217 return ${EXIT_ERROR}
218 fi
219
49958b8c 220 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
1c9e2fa8 221 ENCRYPTION_MODE="${WIRELESS_DEFAULT_ENCRYPTION_MODE}"
49958b8c
MT
222 SSID="${ssid}"
223 PRIORITY=500
224
2f64ac44 225 if ! wireless_network_write_config "${handle}"; then
49958b8c
MT
226 log ERROR "Could not write new config file"
227 return ${EXIT_ERROR}
228 fi
229}
230
4b08d574 231# Deletes a wireless network
49958b8c 232wireless_network_destroy() {
4b08d574
MT
233 local ssid="${1}"
234
235 if ! wireless_network_exists "${ssid}"; then
236 error "No such wireless network: ${ssid}"
237 return ${EXIT_ERROR}
238 fi
239
2f64ac44
MT
240 local handle="$(wireless_network_hash "${ssid}")"
241 assert isset handle
4b08d574 242
2f64ac44 243 if ! rm -rf "${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}"; then
4b08d574
MT
244 error "Could not delete the wireless network"
245 return ${EXIT_ERROR}
246 fi
247
248 log INFO "Successfully destroyed wireless network ${ssid}"
249 return ${EXIT_OK}
49958b8c
MT
250}
251
252wireless_network_encryption_mode() {
253 if [ ! $# -eq 2 ]; then
254 log ERROR "Not enough arguments"
255 return ${EXIT_ERROR}
256 fi
2f64ac44 257 local handle="${1}"
49958b8c
MT
258 local mode="${2}"
259
1c9e2fa8 260 if ! isoneof mode ${WIRELESS_VALID_ENCRYPTION_MODES}; then
49958b8c
MT
261 log ERROR "Encryption mode '${mode}' is invalid"
262 return ${EXIT_ERROR}
263 fi
264
549c5b97 265 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
2f64ac44
MT
266 if ! wireless_network_read_config "${handle}"; then
267 error "Could not read configuration"
549c5b97
MT
268 return ${EXIT_ERROR}
269 fi
270
271 # Validate the PSK when changing mode and reset if needed
272 if isset PSK && [ "${mode}" != "NONE" ] && \
273 ! wireless_pre_shared_key_is_valid "${mode}" "${PSK}"; then
274 log WARNING "The configured pre-shared-key is incompatible with this encryption mode and has been reset"
275 PSK=""
276 fi
277
278 # Save new encryption mode
279 ENCRYPTION_MODE="${mode}"
280
2f64ac44 281 if ! wireless_network_write_config "${handle}"; then
49958b8c
MT
282 log ERROR "Could not write configuration settings"
283 return ${EXIT_ERROR}
284 fi
285}
286
364da6f4 287wireless_network_pre_shared_key() {
49958b8c
MT
288 if [ ! $# -eq 2 ]; then
289 log ERROR "Not enough arguments"
290 return ${EXIT_ERROR}
291 fi
2f64ac44
MT
292
293 local handle="${1}"
364da6f4 294 local psk="${2}"
49958b8c 295
549c5b97 296 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
2f64ac44
MT
297 if ! wireless_network_read_config "${handle}"; then
298 error "Could not read configuration"
549c5b97
MT
299 return ${EXIT_ERROR}
300 fi
301
302 # Validate the key if encryption mode is known
303 if isset ENCRYPTION_MODE && [ "${ENCRYPTION_MODE}" != "NONE" ]; then
304 if ! wireless_pre_share_key_is_valid "${ENCRYPTION_MODE}" "${psk}"; then
305 error "The pre-shared-key is invalid for this wireless network: ${psk}"
306 return ${EXIT_ERROR}
307 fi
308 fi
309
2f64ac44 310 if ! wireless_network_write_config_key "${handle}" "PSK" "${psk}"; then
49958b8c
MT
311 log ERROR "Could not write configuration settings"
312 return ${EXIT_ERROR}
313 fi
314}
315
316wireless_network_priority() {
317 if [ ! $# -eq 2 ]; then
318 log ERROR "Not enough arguments"
319 return ${EXIT_ERROR}
320 fi
2f64ac44
MT
321
322 local handle="${1}"
49958b8c
MT
323 local priority=${2}
324
325 if ! isinteger priority && [ ! ${priority} -ge 0 ]; then
326 log ERROR "The priority must be an integer greater or eqal zero"
327 return ${EXIT_ERROR}
328 fi
329
2f64ac44 330 if ! wireless_network_write_config_key "${handle}" "PRIORITY" "${priority}"; then
49958b8c
MT
331 log ERROR "Could not write configuration settings"
332 return ${EXIT_ERROR}
333 fi
334}
d86b2dee 335
e66e539b
MT
336wireless_networks_write_wpa_supplicant_configuration() {
337 local device="${1}"
338
339 local file="${WPA_SUPPLICANT_CONF_DIR}/${device}.conf"
340
341 # Ensure we can write the file
342 make_parent_directory "${file}"
343
344 local country="$(wireless_get_reg_domain)"
345
346 (
347 config_header "WPA supplicant configuration file"
348
e3a82df1
MT
349 # Set control socket directory.
350 print "ctrl_interface=${WPA_SUPPLICANT_SOCKET_DIR}"
351
e66e539b
MT
352 # Honour country
353 if isset country; then
354 print "country=${country}"
355 print
356 fi
357
358 wireless_networks_to_wpa_supplicant
359 ) > ${file}
360}
361
d86b2dee 362wireless_networks_to_wpa_supplicant() {
2f64ac44
MT
363 local handle
364 for handle in $(wireless_network_list); do
365 wireless_network_to_wpa_supplicant "${handle}"
d86b2dee
MT
366 done
367}
368
369wireless_network_to_wpa_supplicant() {
2f64ac44 370 local handle="${1}"
d86b2dee
MT
371
372 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
2f64ac44
MT
373 if ! wireless_network_read_config "${handle}"; then
374 error "Could not read configuration for ${handle}"
d86b2dee
MT
375 return ${EXIT_ERROR}
376 fi
377
378 local auth_alg
379 local group
380 local key_mgmt
381 local pairwise
382 local proto
383
790ab927
MT
384 local mode
385 for mode in ${WIRELESS_NETWORK_SUPPORTED_MODES}; do
386 # Skip any disabled modes
387 if isset ENCRYPTION_MODES && ! list_match "${mode}" ${ENCRYPTION_MODES}; then
388 continue
389 fi
d86b2dee 390
790ab927
MT
391 case "${mode}" in
392 # WPA2 (802.11i)
393 WPA2-PSK|WPA2-PSK-SHA256)
394 list_append_unique auth_alg "OPEN"
395 list_append_unique key_mgmt "${mode/WPA2/WPA}"
396 list_append_unique proto "RSN"
397
398 local p
399 for p in CCMP TKIP; do
400 list_append_unique pairwise "${p}"
401 done
402
403 local g
404 for g in CCMP TKIP WEP104 WEP40; do
405 list_append_unique group "${g}"
406 done
407 ;;
408
409 # WPA
410 WPA-PSK|WPA-PSK-SHA256)
411 list_append_unique auth_alg "OPEN"
412 list_append_unique key_mgmt "${mode}"
413 list_append_unique proto "WPA"
414
415 local p
416 for p in CCMP TKIP; do
417 list_append_unique pairwise "${p}"
418 done
419
420 local g
421 for g in CCMP TKIP WEP104 WEP40; do
422 list_append_unique group "${g}"
423 done
424 ;;
425
426 # No encryption. DANGEROUS!
427 NONE)
428 list_append_unique auth_alg "OPEN"
429 list_append_unique key_mgmt "NONE"
430 ;;
431 esac
432 done
d86b2dee 433
790ab927
MT
434 assert isset auth_alg
435 assert isset key_mgmt
d86b2dee
MT
436
437 print_indent 0 "# ${SSID}"
d8d0eefc 438 print_indent 0 "network={"
2f64ac44 439 print_indent 1 "ssid=\"${SSID}\""
028a39d1
MT
440
441 # Priority
442 if isinteger PRIORITY; then
443 print_indent 1 "priority=${PRIORITY}"
444 fi
d86b2dee
MT
445 print
446
447 # Authentication
448 print_indent 1 "# Authentication"
449 print_indent 1 "auth_alg=${auth_alg}"
450 print_indent 1 "key_mgmt=${key_mgmt}"
451
790ab927
MT
452 local i
453 for i in proto pairwise group; do
454 print_indent 1 "${i}=${!i}"
455 done
456 print
d86b2dee 457
790ab927
MT
458 # PSK
459 if isset PSK; then
460 print_indent 1 "# Pre Shared Key"
461 print_indent 1 "psk=\"${PSK}\""
462 fi
d86b2dee 463
54948d3c
MT
464 if isset EAP_MODES; then
465 print_indent 1 "# EAP"
466 print_indent 1 "eap=${EAP_MODES}"
467 print
468 fi
469
d86b2dee
MT
470 print_indent 0 "}"
471 print
472}