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