]> git.ipfire.org Git - people/ms/network.git/blob - src/functions/functions.wireless-networks
a9817865b562fdf9fc9013fe8dec93bc4bbf778f
[people/ms/network.git] / src / functions / functions.wireless-networks
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
22 WIRELESS_NETWORK_SUPPORTED_PSK_MODES="WPA2-PSK-SHA256 WPA2-PSK WPA-PSK-SHA256 WPA-PSK"
23
24 WIRELESS_NETWORK_SUPPORTED_MODES="${WIRELESS_NETWORK_SUPPORTED_PSK_MODES} \
25 802.1X WPA-EAP NONE"
26
27 WIRELESS_NETWORK_CONFIG_SETTINGS="ANONYMOUS_IDENTITY EAP_MODES IDENTITY \
28 MODES PASSWORD PRIORITY PSK SSID"
29
30 cli_wireless_network() {
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//-/_}"
41 shift 2
42
43 if ! wireless_network_exists "${ssid}"; then
44 error "No such wireless network: ${ssid}"
45 return ${EXIT_ERROR}
46 fi
47
48 # Convert SSID into usable format
49 local handle="$(wireless_network_hash "${ssid}")"
50
51 case "${key}" in
52 encryption_mode|pre_shared_key|priority)
53 wireless_network_${key} "${handle}" "$@"
54 ;;
55 show)
56 wireless_network_show "${handle}"
57 exit $?
58 ;;
59 *)
60 error "Unrecognized argument: ${key}"
61 exit ${EXIT_ERROR}
62 ;;
63 esac
64 ;;
65 esac
66 }
67
68 wireless_network_list() {
69 list_directory "${NETWORK_WIRELESS_NETWORKS_DIR}"
70 }
71
72 wireless_network_list_ssids() {
73 local handle
74 for handle in $(wireless_network_list); do
75 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
76 if ! wireless_network_read_config "${handle}"; then
77 continue
78 fi
79
80 print "${SSID}"
81 done
82 }
83
84 # This function writes all values to a via ${ssid} specificated wireless network configuration file
85 wireless_network_write_config() {
86 assert [ $# -ge 1 ]
87
88 local handle="${1}"
89
90 local path="${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}/settings"
91
92 if ! settings_write "${path}" ${WIRELESS_NETWORK_CONFIG_SETTINGS}; then
93 log ERROR "Could not write configuration"
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
103 wireless_network_write_config_key() {
104 assert [ $# -ge 3 ]
105
106 local handle="${1}"
107 local key="${2}"
108 shift 2
109
110 local value="$@"
111
112 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
113
114 # Read the config settings
115 if ! wireless_network_read_config "${handle}"; then
116 return ${EXIT_ERROR}
117 fi
118
119 log DEBUG "Set '${key}' to new value '${value}' in wireless network '${SSID}'"
120
121 # Set the key to a new value
122 assign "${key}" "${value}"
123
124 if ! wireless_network_write_config "${handle}"; then
125 return ${EXIT_ERROR}
126 fi
127
128 return ${EXIT_OK}
129 }
130
131 # Reads one or more keys out of a settings file or all if no key is provided.
132 wireless_network_read_config() {
133 assert [ $# -ge 1 ]
134
135 local handle="${1}"
136 shift
137
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
145 local path="${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}/settings"
146
147 if ! settings_read "${path}" ${args}; then
148 log ERROR "Could not read settings for wireless network ${handle}"
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
155 wireless_network_exists() {
156 local ssid="${1}"
157
158 local handle="$(wireless_network_hash "${ssid}")"
159 assert isset handle
160
161 # We cannot use wireless_network_read_config here beacuse we would end in a loop
162 local SSID
163 if ! settings_read "${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}/settings" SSID; then
164 return ${EXIT_FALSE}
165 fi
166
167 if [ "${SSID}" = "${ssid}" ]; then
168 return ${EXIT_TRUE}
169 else
170 return ${EXIT_FALSE}
171 fi
172 }
173
174 wireless_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
193 wireless_network_new() {
194 if [ $# -gt 1 ]; then
195 error "Too many arguments"
196 return ${EXIT_ERROR}
197 fi
198
199 local ssid="${1}"
200
201 if ! isset ssid; then
202 error "Please provide a SSID"
203 return ${EXIT_ERROR}
204 fi
205
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
212 local handle="$(wireless_network_hash "${ssid}")"
213 assert isset handle
214
215 log DEBUG "Creating wireless network '${ssid}'"
216
217 if ! mkdir -p "${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}"; then
218 log ERROR "Could not create config directory for wireless network ${ssid}"
219 return ${EXIT_ERROR}
220 fi
221
222 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
223 ENCRYPTION_MODE="${WIRELESS_DEFAULT_ENCRYPTION_MODE}"
224 SSID="${ssid}"
225 PRIORITY=0
226
227 if ! wireless_network_write_config "${handle}"; then
228 log ERROR "Could not write new config file"
229 return ${EXIT_ERROR}
230 fi
231 }
232
233 # Deletes a wireless network
234 wireless_network_destroy() {
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
242 local handle="$(wireless_network_hash "${ssid}")"
243 assert isset handle
244
245 if ! rm -rf "${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}"; then
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}
252 }
253
254 wireless_network_encryption_mode() {
255 if [ ! $# -eq 2 ]; then
256 log ERROR "Not enough arguments"
257 return ${EXIT_ERROR}
258 fi
259 local handle="${1}"
260 local mode="${2}"
261
262 if ! isoneof mode ${WIRELESS_VALID_ENCRYPTION_MODES}; then
263 log ERROR "Encryption mode '${mode}' is invalid"
264 return ${EXIT_ERROR}
265 fi
266
267 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
268 if ! wireless_network_read_config "${handle}"; then
269 error "Could not read configuration"
270 return ${EXIT_ERROR}
271 fi
272
273 # Validate the PSK when changing mode and reset if needed
274 if isset PSK && [ "${mode}" != "NONE" ] && \
275 ! wireless_pre_shared_key_is_valid "${mode}" "${PSK}"; then
276 log WARNING "The configured pre-shared-key is incompatible with this encryption mode and has been reset"
277 PSK=""
278 fi
279
280 # Save new encryption mode
281 ENCRYPTION_MODE="${mode}"
282
283 if ! wireless_network_write_config "${handle}"; then
284 log ERROR "Could not write configuration settings"
285 return ${EXIT_ERROR}
286 fi
287 }
288
289 wireless_network_pre_shared_key() {
290 if [ ! $# -eq 2 ]; then
291 log ERROR "Not enough arguments"
292 return ${EXIT_ERROR}
293 fi
294
295 local handle="${1}"
296 local psk="${2}"
297
298 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
299 if ! wireless_network_read_config "${handle}"; then
300 error "Could not read configuration"
301 return ${EXIT_ERROR}
302 fi
303
304 # Validate the key if encryption mode is known
305 if isset ENCRYPTION_MODE && [ "${ENCRYPTION_MODE}" != "NONE" ]; then
306 if ! wireless_pre_share_key_is_valid "${ENCRYPTION_MODE}" "${psk}"; then
307 error "The pre-shared-key is invalid for this wireless network: ${psk}"
308 return ${EXIT_ERROR}
309 fi
310 fi
311
312 if ! wireless_network_write_config_key "${handle}" "PSK" "${psk}"; then
313 log ERROR "Could not write configuration settings"
314 return ${EXIT_ERROR}
315 fi
316 }
317
318 wireless_network_priority() {
319 if [ ! $# -eq 2 ]; then
320 log ERROR "Not enough arguments"
321 return ${EXIT_ERROR}
322 fi
323
324 local handle="${1}"
325 local priority=${2}
326
327 if ! isinteger priority && [ ! ${priority} -ge 0 ]; then
328 log ERROR "The priority must be an integer greater or eqal zero"
329 return ${EXIT_ERROR}
330 fi
331
332 if ! wireless_network_write_config_key "${handle}" "PRIORITY" "${priority}"; then
333 log ERROR "Could not write configuration settings"
334 return ${EXIT_ERROR}
335 fi
336 }
337
338 wireless_networks_write_wpa_supplicant_configuration() {
339 local device="${1}"
340
341 local file="${WPA_SUPPLICANT_CONF_DIR}/${device}.conf"
342
343 # Ensure we can write the file
344 make_parent_directory "${file}"
345
346 (
347 # Write a config header
348 wpa_supplicant_config_header
349
350 wireless_networks_to_wpa_supplicant
351 ) > ${file}
352 }
353
354 wireless_networks_to_wpa_supplicant() {
355 local handle
356 for handle in $(wireless_network_list); do
357 wireless_network_to_wpa_supplicant "${handle}"
358 done
359 }
360
361 wireless_network_to_wpa_supplicant() {
362 local handle="${1}"
363
364 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
365 if ! wireless_network_read_config "${handle}"; then
366 error "Could not read configuration for ${handle}"
367 return ${EXIT_ERROR}
368 fi
369
370 local auth_alg
371 local group
372 local key_mgmt
373 local pairwise
374 local proto
375
376 local mode
377 for mode in ${WIRELESS_NETWORK_SUPPORTED_MODES}; do
378 # Skip any disabled modes
379 if isset MODES && ! list_match "${mode}" ${MODES}; then
380 continue
381 fi
382
383 case "${mode}" in
384 # WPA2 (802.11i)
385 WPA2-PSK|WPA2-PSK-SHA256)
386 list_append_unique auth_alg "OPEN"
387 list_append_unique key_mgmt "${mode/WPA2/WPA}"
388 list_append_unique proto "RSN"
389
390 local p
391 for p in CCMP TKIP; do
392 list_append_unique pairwise "${p}"
393 done
394
395 local g
396 for g in CCMP TKIP WEP104 WEP40; do
397 list_append_unique group "${g}"
398 done
399 ;;
400
401 # WPA
402 WPA-PSK|WPA-PSK-SHA256)
403 list_append_unique auth_alg "OPEN"
404 list_append_unique key_mgmt "${mode}"
405 list_append_unique proto "WPA"
406
407 local p
408 for p in CCMP TKIP; do
409 list_append_unique pairwise "${p}"
410 done
411
412 local g
413 for g in CCMP TKIP WEP104 WEP40; do
414 list_append_unique group "${g}"
415 done
416 ;;
417
418 # 802.1X
419 802.1X)
420 list_append_unique key_mgmt "IEEE8021X"
421 ;;
422
423 # No encryption. DANGEROUS!
424 NONE)
425 list_append_unique auth_alg "OPEN"
426 list_append_unique key_mgmt "NONE"
427 ;;
428 esac
429 done
430
431 assert isset auth_alg
432 assert isset key_mgmt
433
434 # Read CA certificate
435 local ca_cert_path="${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}/ca.pem"
436
437 print_indent 0 "# ${SSID}"
438 print_indent 0 "network={"
439 print_indent 1 "ssid=\"${SSID}\""
440
441 # Priority
442 if isinteger PRIORITY; then
443 print_indent 1 "priority=${PRIORITY}"
444 fi
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
452 local i
453 for i in proto pairwise group; do
454 print_indent 1 "${i}=${!i}"
455 done
456 print
457
458 # PSK
459 if isset PSK; then
460 print_indent 1 "# Pre Shared Key"
461 print_indent 1 "psk=\"${PSK}\""
462 fi
463
464 if isset EAP_MODES; then
465 print_indent 1 "# EAP"
466 print_indent 1 "eap=${EAP_MODES}"
467 print
468 fi
469
470 if isset IDENTITY; then
471 print_indent 1 "# Credentials"
472 print_indent 1 "identity=\"${IDENTITY}\""
473
474 if isset PASSWORD; then
475 print_indent 1 "password=\"${PASSWORD}\""
476 fi
477
478 if isset ANONYMOUS_IDENTITY; then
479 print_indent 1 "anonymous_identity=\"${ANONYMOUS_IDENTITY}\""
480 fi
481 print
482 fi
483
484 # Validate server certificates
485 if file_exists "${ca_cert_path}"; then
486 print_indent 1 "ca_cert=\"${ca_cert_path}\""
487
488 elif isset CA_BUNDLE; then
489 print_indent 1 "ca_cert=\"${CA_BUNDLE}\""
490 fi
491
492 print_indent 0 "}"
493 print
494 }