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