]> git.ipfire.org Git - people/stevee/network.git/blame - src/functions/functions.wireless-networks
Fix creating new configs
[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
8225ab51
MT
24WIRELESS_NETWORK_SUPPORTED_MODES="${WIRELESS_NETWORK_SUPPORTED_PSK_MODES} \
25 802.1X WPA-EAP NONE"
790ab927 26
71afcc9d
MT
27WIRELESS_NETWORK_CONFIG_SETTINGS="ANONYMOUS_IDENTITY EAP_MODES HIDDEN \
28 IDENTITY MODES PASSWORD PRIORITY PSK SSID"
49958b8c 29
49958b8c 30cli_wireless_network() {
479b2273
MT
31 case "${1}" in
32 new)
33 wireless_network_new "${@:2}"
34 ;;
35 destroy)
36 wireless_network_destroy "${@:2}"
37 ;;
38 *)
39 local ssid="${1}"
40 local key="${2//-/_}"
549c5b97 41 shift 2
49958b8c 42
479b2273
MT
43 if ! wireless_network_exists "${ssid}"; then
44 error "No such wireless network: ${ssid}"
45 return ${EXIT_ERROR}
46 fi
49958b8c 47
2f64ac44
MT
48 # Convert SSID into usable format
49 local handle="$(wireless_network_hash "${ssid}")"
50
479b2273 51 case "${key}" in
77a710b0 52 modes|pre_shared_key|priority)
2f64ac44 53 wireless_network_${key} "${handle}" "$@"
479b2273
MT
54 ;;
55 show)
2f64ac44 56 wireless_network_show "${handle}"
479b2273
MT
57 exit $?
58 ;;
59 *)
60 error "Unrecognized argument: ${key}"
61 exit ${EXIT_ERROR}
62 ;;
63 esac
64 ;;
65 esac
49958b8c
MT
66}
67
d86b2dee
MT
68wireless_network_list() {
69 list_directory "${NETWORK_WIRELESS_NETWORKS_DIR}"
70}
71
72wireless_network_list_ssids() {
73 local handle
74 for handle in $(wireless_network_list); do
75 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
2f64ac44 76 if ! wireless_network_read_config "${handle}"; then
d86b2dee
MT
77 continue
78 fi
79
80 print "${SSID}"
81 done
82}
83
49958b8c
MT
84# This function writes all values to a via ${ssid} specificated wireless network configuration file
85wireless_network_write_config() {
86 assert [ $# -ge 1 ]
87
2f64ac44 88 local handle="${1}"
49958b8c 89
2f64ac44 90 local path="${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}/settings"
49958b8c
MT
91
92 if ! settings_write "${path}" ${WIRELESS_NETWORK_CONFIG_SETTINGS}; then
2f64ac44 93 log ERROR "Could not write configuration"
49958b8c
MT
94 return ${EXIT_ERROR}
95 fi
96
97 # When we get here the writing of the config file was successful
98 return ${EXIT_OK}
99}
100
101# This funtion writes the value for one key to a via ${ssid} specificated
102# wireless network configuration file
103wireless_network_write_config_key() {
104 assert [ $# -ge 3 ]
105
2f64ac44 106 local handle="${1}"
49958b8c
MT
107 local key="${2}"
108 shift 2
109
110 local value="$@"
111
49958b8c
MT
112 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
113
114 # Read the config settings
2f64ac44 115 if ! wireless_network_read_config "${handle}"; then
49958b8c
MT
116 return ${EXIT_ERROR}
117 fi
118
2f64ac44
MT
119 log DEBUG "Set '${key}' to new value '${value}' in wireless network '${SSID}'"
120
49958b8c
MT
121 # Set the key to a new value
122 assign "${key}" "${value}"
123
2f64ac44 124 if ! wireless_network_write_config "${handle}"; then
49958b8c
MT
125 return ${EXIT_ERROR}
126 fi
127
128 return ${EXIT_OK}
129}
130
d86b2dee 131# Reads one or more keys out of a settings file or all if no key is provided.
2f64ac44 132wireless_network_read_config() {
d86b2dee
MT
133 assert [ $# -ge 1 ]
134
135 local handle="${1}"
136 shift
137
49958b8c
MT
138 local args
139 if [ $# -eq 0 ] && [ -n "${WIRELESS_NETWORK_CONFIG_SETTINGS}" ]; then
140 list_append args ${WIRELESS_NETWORK_CONFIG_SETTINGS}
141 else
142 list_append args "$@"
143 fi
144
d86b2dee 145 local path="${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}/settings"
49958b8c
MT
146
147 if ! settings_read "${path}" ${args}; then
d86b2dee 148 log ERROR "Could not read settings for wireless network ${handle}"
49958b8c
MT
149 return ${EXIT_ERROR}
150 fi
151}
152
153# This function checks if a wireless network exists
154# Returns True when yes and false when not
155wireless_network_exists() {
49958b8c 156 local ssid="${1}"
49958b8c 157
2f64ac44
MT
158 local handle="$(wireless_network_hash "${ssid}")"
159 assert isset handle
49958b8c
MT
160
161 # We cannot use wireless_network_read_config here beacuse we would end in a loop
162 local SSID
2f64ac44 163 if ! settings_read "${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}/settings" SSID; then
49958b8c
MT
164 return ${EXIT_FALSE}
165 fi
166
2f64ac44 167 if [ "${SSID}" = "${ssid}" ]; then
49958b8c
MT
168 return ${EXIT_TRUE}
169 else
170 return ${EXIT_FALSE}
171 fi
172}
173
174wireless_network_hash() {
175 assert [ $# -eq 1 ]
176
177 local string="${1}"
178
179 local hash=$(echo -n "${string}" | md5sum )
180 hash=${hash%% -}
181
182 local path="${NETWORK_WIRELESS_NETWORKS_DIR}/*${hash}"
183
184 if [ -d "${path}" ]; then
185 basename "${path}"
186 else
187 local normalized=$(normalize "${string}")
188 normalized=${normalized%-}
189 echo "${normalized}-${hash}"
190 fi
191}
192
193wireless_network_new() {
194 if [ $# -gt 1 ]; then
195 error "Too many arguments"
196 return ${EXIT_ERROR}
197 fi
198
199 local ssid="${1}"
2f64ac44 200
49958b8c
MT
201 if ! isset ssid; then
202 error "Please provide a SSID"
203 return ${EXIT_ERROR}
204 fi
205
49958b8c
MT
206 # Check for duplicates
207 if wireless_network_exists "${ssid}"; then
208 error "The wireless network ${ssid} already exists"
209 return ${EXIT_ERROR}
210 fi
211
2f64ac44
MT
212 local handle="$(wireless_network_hash "${ssid}")"
213 assert isset handle
214
49958b8c
MT
215 log DEBUG "Creating wireless network '${ssid}'"
216
2f64ac44 217 if ! mkdir -p "${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}"; then
49958b8c
MT
218 log ERROR "Could not create config directory for wireless network ${ssid}"
219 return ${EXIT_ERROR}
220 fi
221
49958b8c 222 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
e83e2636 223 MODES="${WIRELESS_NETWORK_SUPPORTED_MODES}"
49958b8c 224 SSID="${ssid}"
a8c26c3d 225 PRIORITY=0
49958b8c 226
2f64ac44 227 if ! wireless_network_write_config "${handle}"; then
49958b8c
MT
228 log ERROR "Could not write new config file"
229 return ${EXIT_ERROR}
230 fi
231}
232
4b08d574 233# Deletes a wireless network
49958b8c 234wireless_network_destroy() {
4b08d574
MT
235 local ssid="${1}"
236
237 if ! wireless_network_exists "${ssid}"; then
238 error "No such wireless network: ${ssid}"
239 return ${EXIT_ERROR}
240 fi
241
2f64ac44
MT
242 local handle="$(wireless_network_hash "${ssid}")"
243 assert isset handle
4b08d574 244
2f64ac44 245 if ! rm -rf "${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}"; then
4b08d574
MT
246 error "Could not delete the wireless network"
247 return ${EXIT_ERROR}
248 fi
249
250 log INFO "Successfully destroyed wireless network ${ssid}"
251 return ${EXIT_OK}
49958b8c
MT
252}
253
77a710b0
JS
254wireless_networks_mode_is_valid() {
255 assert [ $# -eq 1 ]
256 local mode=${1}
257
258 if isoneof mode ${WIRELESS_NETWORK_SUPPORTED_MODES}; then
259 return ${EXIT_TRUE}
260 else
261 return ${EXIT_FALSE}
262 fi
263
264}
265
266# WIRELESS_NETWORK_SUPPORTED_MODES
267wireless_network_modes() {
268 if [ ! $# -ge 2 ]; then
49958b8c
MT
269 log ERROR "Not enough arguments"
270 return ${EXIT_ERROR}
271 fi
2f64ac44 272 local handle="${1}"
77a710b0 273 shift
49958b8c 274
77a710b0
JS
275 if [ $# -eq 0 ]; then
276 log ERROR "You must pass at least one value after mode"
49958b8c
MT
277 return ${EXIT_ERROR}
278 fi
279
549c5b97 280 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
2f64ac44
MT
281 if ! wireless_network_read_config "${handle}"; then
282 error "Could not read configuration"
549c5b97
MT
283 return ${EXIT_ERROR}
284 fi
285
77a710b0
JS
286 # Remove duplicated entries to proceed the list safely
287 MODES="$(list_unique ${MODES})"
288
289 local modes_added
290 local modes_removed
291 local modes_set
292
293 while [ $# -gt 0 ]; do
294 local arg="${1}"
295
296 case "${arg}" in
297 +*)
298 list_append modes_added "${arg:1}"
299 ;;
300 -*)
301 list_append modes_removed "${arg:1}"
302 ;;
303 [A-Z0-9]*)
304 list_append modes_set "${arg}"
305 ;;
306 *)
307 error "Invalid argument: ${arg}"
308 return ${EXIT_ERROR}
309 ;;
310 esac
311 shift
312 done
313
314 # Check if the user is trying a mixed operation
315 if ! list_is_empty modes_set && (! list_is_empty modes_added || ! list_is_empty modes_removed); then
316 error "You cannot reset the modes list and add or remove modes at the same time"
317 return ${EXIT_ERROR}
549c5b97
MT
318 fi
319
77a710b0
JS
320 # Set new modes list
321 if ! list_is_empty modes_set; then
322 # Check if all modes are valid
323 local mode
324 for mode in ${modes_set}; do
325 if ! wireless_networks_mode_is_valid ${mode}; then
326 error "Unsupported mode: ${mode}"
327 return ${EXIT_ERROR}
328 fi
329 done
330
331 MODES="${modes_set}"
332
333 # Perform incremental updates
334 else
335 local modes
336
337 # Perform all removals
338 for mode in ${modes_removed}; do
339 if ! list_remove MODES ${mode}; then
340 warning "${mode} was not on the list and could not be removed"
341 fi
342 done
343
344 for mode in ${modes_added}; do
345 if wireless_networks_mode_is_valid ${mode}; then
346 if ! list_append_unique MODES ${mode}; then
347 warning "${mode} is already on the modes list"
348 fi
349 else
350 warning "${mode} is unknown or unsupported and could not be added"
351 fi
352 done
353 fi
354
355 # Check if the list contain at least one valid mode
356 if list_is_empty MODES; then
357 error "Cannot save an empty mode list"
358 return ${EXIT_ERROR}
359 fi
549c5b97 360
2f64ac44 361 if ! wireless_network_write_config "${handle}"; then
49958b8c
MT
362 log ERROR "Could not write configuration settings"
363 return ${EXIT_ERROR}
364 fi
365}
366
364da6f4 367wireless_network_pre_shared_key() {
49958b8c
MT
368 if [ ! $# -eq 2 ]; then
369 log ERROR "Not enough arguments"
370 return ${EXIT_ERROR}
371 fi
2f64ac44
MT
372
373 local handle="${1}"
364da6f4 374 local psk="${2}"
49958b8c 375
549c5b97 376 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
2f64ac44
MT
377 if ! wireless_network_read_config "${handle}"; then
378 error "Could not read configuration"
549c5b97
MT
379 return ${EXIT_ERROR}
380 fi
381
382 # Validate the key if encryption mode is known
383 if isset ENCRYPTION_MODE && [ "${ENCRYPTION_MODE}" != "NONE" ]; then
384 if ! wireless_pre_share_key_is_valid "${ENCRYPTION_MODE}" "${psk}"; then
385 error "The pre-shared-key is invalid for this wireless network: ${psk}"
386 return ${EXIT_ERROR}
387 fi
388 fi
389
2f64ac44 390 if ! wireless_network_write_config_key "${handle}" "PSK" "${psk}"; then
49958b8c
MT
391 log ERROR "Could not write configuration settings"
392 return ${EXIT_ERROR}
393 fi
394}
395
3a987fa6
JS
396wireless_networks_priority_is_valid() {
397 assert [ $# -eq 1 ]
398
399 local priority=${1}
400
401 if ! isinteger priority || [ ! ${priority} -ge 0 ] || [ ! ${priority} -le 999 ]; then
402 return ${EXIT_FALSE}
403 fi
404
405 return ${EXIT_TRUE}
406}
407
49958b8c
MT
408wireless_network_priority() {
409 if [ ! $# -eq 2 ]; then
410 log ERROR "Not enough arguments"
411 return ${EXIT_ERROR}
412 fi
2f64ac44
MT
413
414 local handle="${1}"
49958b8c
MT
415 local priority=${2}
416
3a987fa6
JS
417 if ! wireless_networks_priority_is_valid ${priority}; then
418 error "The priority must be an integer greater or eqal zero and and less then 1000"
49958b8c
MT
419 return ${EXIT_ERROR}
420 fi
421
2f64ac44 422 if ! wireless_network_write_config_key "${handle}" "PRIORITY" "${priority}"; then
49958b8c
MT
423 log ERROR "Could not write configuration settings"
424 return ${EXIT_ERROR}
425 fi
426}
d86b2dee 427
e66e539b
MT
428wireless_networks_write_wpa_supplicant_configuration() {
429 local device="${1}"
430
431 local file="${WPA_SUPPLICANT_CONF_DIR}/${device}.conf"
432
433 # Ensure we can write the file
434 make_parent_directory "${file}"
435
e66e539b 436 (
f1b49125
MT
437 # Write a config header
438 wpa_supplicant_config_header
e66e539b
MT
439
440 wireless_networks_to_wpa_supplicant
441 ) > ${file}
442}
443
d86b2dee 444wireless_networks_to_wpa_supplicant() {
2f64ac44
MT
445 local handle
446 for handle in $(wireless_network_list); do
447 wireless_network_to_wpa_supplicant "${handle}"
d86b2dee
MT
448 done
449}
450
451wireless_network_to_wpa_supplicant() {
2f64ac44 452 local handle="${1}"
d86b2dee
MT
453
454 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
2f64ac44
MT
455 if ! wireless_network_read_config "${handle}"; then
456 error "Could not read configuration for ${handle}"
d86b2dee
MT
457 return ${EXIT_ERROR}
458 fi
459
460 local auth_alg
461 local group
462 local key_mgmt
463 local pairwise
464 local proto
465
790ab927
MT
466 local mode
467 for mode in ${WIRELESS_NETWORK_SUPPORTED_MODES}; do
468 # Skip any disabled modes
0afdbac2 469 if isset MODES && ! list_match "${mode}" ${MODES}; then
790ab927
MT
470 continue
471 fi
d86b2dee 472
790ab927
MT
473 case "${mode}" in
474 # WPA2 (802.11i)
475 WPA2-PSK|WPA2-PSK-SHA256)
476 list_append_unique auth_alg "OPEN"
477 list_append_unique key_mgmt "${mode/WPA2/WPA}"
478 list_append_unique proto "RSN"
479
480 local p
481 for p in CCMP TKIP; do
482 list_append_unique pairwise "${p}"
483 done
484
485 local g
486 for g in CCMP TKIP WEP104 WEP40; do
487 list_append_unique group "${g}"
488 done
489 ;;
490
491 # WPA
492 WPA-PSK|WPA-PSK-SHA256)
493 list_append_unique auth_alg "OPEN"
494 list_append_unique key_mgmt "${mode}"
495 list_append_unique proto "WPA"
496
497 local p
498 for p in CCMP TKIP; do
499 list_append_unique pairwise "${p}"
500 done
501
502 local g
503 for g in CCMP TKIP WEP104 WEP40; do
504 list_append_unique group "${g}"
505 done
506 ;;
507
fa25d793
MT
508 # 802.1X
509 802.1X)
510 list_append_unique key_mgmt "IEEE8021X"
511 ;;
512
790ab927
MT
513 # No encryption. DANGEROUS!
514 NONE)
515 list_append_unique auth_alg "OPEN"
516 list_append_unique key_mgmt "NONE"
517 ;;
518 esac
519 done
d86b2dee 520
790ab927
MT
521 assert isset auth_alg
522 assert isset key_mgmt
d86b2dee 523
0da7d566 524 # Certificate Paths
a7dadb04 525 local ca_cert_path="${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}/ca.pem"
0da7d566
MT
526 local client_cert_path="${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}/client.pem"
527 local client_key_path="${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}/client.key"
a7dadb04 528
d86b2dee 529 print_indent 0 "# ${SSID}"
d8d0eefc 530 print_indent 0 "network={"
2f64ac44 531 print_indent 1 "ssid=\"${SSID}\""
028a39d1 532
71afcc9d
MT
533 # Actively scan for hidden networks
534 if enabled HIDDEN; then
535 print_indent 1 "scan_ssid=1"
536 fi
537
028a39d1
MT
538 # Priority
539 if isinteger PRIORITY; then
540 print_indent 1 "priority=${PRIORITY}"
541 fi
d86b2dee
MT
542 print
543
544 # Authentication
545 print_indent 1 "# Authentication"
546 print_indent 1 "auth_alg=${auth_alg}"
547 print_indent 1 "key_mgmt=${key_mgmt}"
548
790ab927
MT
549 local i
550 for i in proto pairwise group; do
551 print_indent 1 "${i}=${!i}"
552 done
553 print
d86b2dee 554
790ab927
MT
555 # PSK
556 if isset PSK; then
557 print_indent 1 "# Pre Shared Key"
558 print_indent 1 "psk=\"${PSK}\""
559 fi
d86b2dee 560
54948d3c
MT
561 if isset EAP_MODES; then
562 print_indent 1 "# EAP"
563 print_indent 1 "eap=${EAP_MODES}"
564 print
565 fi
566
26078fa1
MT
567 if isset IDENTITY; then
568 print_indent 1 "# Credentials"
569 print_indent 1 "identity=\"${IDENTITY}\""
570
571 if isset PASSWORD; then
572 print_indent 1 "password=\"${PASSWORD}\""
573 fi
574
575 if isset ANONYMOUS_IDENTITY; then
576 print_indent 1 "anonymous_identity=\"${ANONYMOUS_IDENTITY}\""
577 fi
578 print
579 fi
580
0da7d566
MT
581 # Client Certificate
582 if file_exists "${client_cert_path}" && file_exists "${client_key_path}"; then
583 print_indent 1 "# Client Certificate"
584 print_indent 1 "client_cert=\"${client_cert_path}\""
585 print_indent 1 "private_key=\"${client_key_path}\""
586 print
587 fi
588
4ed1b754 589 # Validate server certificates
a7dadb04
MT
590 if file_exists "${ca_cert_path}"; then
591 print_indent 1 "ca_cert=\"${ca_cert_path}\""
592
593 elif isset CA_BUNDLE; then
594 print_indent 1 "ca_cert=\"${CA_BUNDLE}\""
4ed1b754
MT
595 fi
596
d86b2dee
MT
597 print_indent 0 "}"
598 print
599}