wpa_supplicant: Doesn't like spaces here
[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_SUPPORTED_PSK_MODES="WPA2-PSK-SHA256 WPA2-PSK WPA-PSK-SHA256 WPA-PSK"
23
24 WIRELESS_NETWORK_SUPPORTED_MODES="${WIRELESS_NETWORK_SUPPORTED_PSK_MODES} NONE"
25
26 WIRELESS_NETWORK_CONFIG_SETTINGS="EAP_MODES ENCRYPTION_MODES PRIORITY PSK SSID"
27
28 cli_wireless_network() {
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//-/_}"
39 shift 2
40
41 if ! wireless_network_exists "${ssid}"; then
42 error "No such wireless network: ${ssid}"
43 return ${EXIT_ERROR}
44 fi
45
46 # Convert SSID into usable format
47 local handle="$(wireless_network_hash "${ssid}")"
48
49 case "${key}" in
50 encryption_mode|pre_shared_key|priority)
51 wireless_network_${key} "${handle}" "$@"
52 ;;
53 show)
54 wireless_network_show "${handle}"
55 exit $?
56 ;;
57 *)
58 error "Unrecognized argument: ${key}"
59 exit ${EXIT_ERROR}
60 ;;
61 esac
62 ;;
63 esac
64 }
65
66 wireless_network_list() {
67 list_directory "${NETWORK_WIRELESS_NETWORKS_DIR}"
68 }
69
70 wireless_network_list_ssids() {
71 local handle
72 for handle in $(wireless_network_list); do
73 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
74 if ! wireless_network_read_config "${handle}"; then
75 continue
76 fi
77
78 print "${SSID}"
79 done
80 }
81
82 # This function writes all values to a via ${ssid} specificated wireless network configuration file
83 wireless_network_write_config() {
84 assert [ $# -ge 1 ]
85
86 local handle="${1}"
87
88 local path="${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}/settings"
89
90 if ! settings_write "${path}" ${WIRELESS_NETWORK_CONFIG_SETTINGS}; then
91 log ERROR "Could not write configuration"
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
101 wireless_network_write_config_key() {
102 assert [ $# -ge 3 ]
103
104 local handle="${1}"
105 local key="${2}"
106 shift 2
107
108 local value="$@"
109
110 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
111
112 # Read the config settings
113 if ! wireless_network_read_config "${handle}"; then
114 return ${EXIT_ERROR}
115 fi
116
117 log DEBUG "Set '${key}' to new value '${value}' in wireless network '${SSID}'"
118
119 # Set the key to a new value
120 assign "${key}" "${value}"
121
122 if ! wireless_network_write_config "${handle}"; then
123 return ${EXIT_ERROR}
124 fi
125
126 return ${EXIT_OK}
127 }
128
129 # Reads one or more keys out of a settings file or all if no key is provided.
130 wireless_network_read_config() {
131 assert [ $# -ge 1 ]
132
133 local handle="${1}"
134 shift
135
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
143 local path="${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}/settings"
144
145 if ! settings_read "${path}" ${args}; then
146 log ERROR "Could not read settings for wireless network ${handle}"
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
153 wireless_network_exists() {
154 local ssid="${1}"
155
156 local handle="$(wireless_network_hash "${ssid}")"
157 assert isset handle
158
159 # We cannot use wireless_network_read_config here beacuse we would end in a loop
160 local SSID
161 if ! settings_read "${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}/settings" SSID; then
162 return ${EXIT_FALSE}
163 fi
164
165 if [ "${SSID}" = "${ssid}" ]; then
166 return ${EXIT_TRUE}
167 else
168 return ${EXIT_FALSE}
169 fi
170 }
171
172 wireless_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
191 wireless_network_new() {
192 if [ $# -gt 1 ]; then
193 error "Too many arguments"
194 return ${EXIT_ERROR}
195 fi
196
197 local ssid="${1}"
198
199 if ! isset ssid; then
200 error "Please provide a SSID"
201 return ${EXIT_ERROR}
202 fi
203
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
210 local handle="$(wireless_network_hash "${ssid}")"
211 assert isset handle
212
213 log DEBUG "Creating wireless network '${ssid}'"
214
215 if ! mkdir -p "${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}"; then
216 log ERROR "Could not create config directory for wireless network ${ssid}"
217 return ${EXIT_ERROR}
218 fi
219
220 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
221 ENCRYPTION_MODE="${WIRELESS_DEFAULT_ENCRYPTION_MODE}"
222 SSID="${ssid}"
223 PRIORITY=500
224
225 if ! wireless_network_write_config "${handle}"; then
226 log ERROR "Could not write new config file"
227 return ${EXIT_ERROR}
228 fi
229 }
230
231 # Deletes a wireless network
232 wireless_network_destroy() {
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
240 local handle="$(wireless_network_hash "${ssid}")"
241 assert isset handle
242
243 if ! rm -rf "${NETWORK_WIRELESS_NETWORKS_DIR}/${handle}"; then
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}
250 }
251
252 wireless_network_encryption_mode() {
253 if [ ! $# -eq 2 ]; then
254 log ERROR "Not enough arguments"
255 return ${EXIT_ERROR}
256 fi
257 local handle="${1}"
258 local mode="${2}"
259
260 if ! isoneof mode ${WIRELESS_VALID_ENCRYPTION_MODES}; then
261 log ERROR "Encryption mode '${mode}' is invalid"
262 return ${EXIT_ERROR}
263 fi
264
265 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
266 if ! wireless_network_read_config "${handle}"; then
267 error "Could not read configuration"
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
281 if ! wireless_network_write_config "${handle}"; then
282 log ERROR "Could not write configuration settings"
283 return ${EXIT_ERROR}
284 fi
285 }
286
287 wireless_network_pre_shared_key() {
288 if [ ! $# -eq 2 ]; then
289 log ERROR "Not enough arguments"
290 return ${EXIT_ERROR}
291 fi
292
293 local handle="${1}"
294 local psk="${2}"
295
296 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
297 if ! wireless_network_read_config "${handle}"; then
298 error "Could not read configuration"
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
310 if ! wireless_network_write_config_key "${handle}" "PSK" "${psk}"; then
311 log ERROR "Could not write configuration settings"
312 return ${EXIT_ERROR}
313 fi
314 }
315
316 wireless_network_priority() {
317 if [ ! $# -eq 2 ]; then
318 log ERROR "Not enough arguments"
319 return ${EXIT_ERROR}
320 fi
321
322 local handle="${1}"
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
330 if ! wireless_network_write_config_key "${handle}" "PRIORITY" "${priority}"; then
331 log ERROR "Could not write configuration settings"
332 return ${EXIT_ERROR}
333 fi
334 }
335
336 wireless_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
349 # Set control socket directory.
350 print "ctrl_interface=${WPA_SUPPLICANT_SOCKET_DIR}"
351
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
362 wireless_networks_to_wpa_supplicant() {
363 local handle
364 for handle in $(wireless_network_list); do
365 wireless_network_to_wpa_supplicant "${handle}"
366 done
367 }
368
369 wireless_network_to_wpa_supplicant() {
370 local handle="${1}"
371
372 local ${WIRELESS_NETWORK_CONFIG_SETTINGS}
373 if ! wireless_network_read_config "${handle}"; then
374 error "Could not read configuration for ${handle}"
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 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
390
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
433
434 assert isset auth_alg
435 assert isset key_mgmt
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 print_indent 0 "}"
471 print
472 }