]> git.ipfire.org Git - people/ms/network.git/commitdiff
security-polices: Improve modification of cipher lists
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 21 Jul 2017 19:15:08 +0000 (21:15 +0200)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 21 Jul 2017 20:10:10 +0000 (22:10 +0200)
This now supports setting a cipher list in one command and returns
some useful warnings when an intended change could not be performed.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/functions/functions.list
src/functions/functions.vpn-security-policies

index ff73b04e0f737474cd736c823cb8096d38059137..e65bbd33a541647e37c6c74d5314d42253d9b831 100644 (file)
 # Functions for nice handling of lists.
 #
 
+list_set() {
+       local list=${1}
+       shift
+
+       assign "${list}" "$@"
+}
+
 list_append() {
        local list=${1}
        assert isset list
@@ -50,6 +57,28 @@ list_append_one() {
        fi
 }
 
+# Appends one or more elements to the list only if they are not on the list, yet
+list_append_unique() {
+       local list=${1}
+       shift
+
+       assert isset list
+
+       local ret=${EXIT_ERROR}
+
+       local arg
+       for arg in $@; do
+               if ! list_match ${arg} ${!list}; then
+                       list_append_one ${list} "${arg}"
+                       ret=${EXIT_OK}
+               fi
+       done
+
+       return ${ret}
+}
+
+# Removes all matching items from the list
+# Returns OK if at least one match was found and ERROR when not
 list_remove() {
        local list=${1}
        shift
@@ -57,14 +86,21 @@ list_remove() {
        assert isset list
        assert [ ${list} != "list" ]
 
+       local ret=${EXIT_ERROR}
+
        local _list k
        for k in ${!list}; do
-               list_match ${k} $@ && continue
+               if list_match ${k} $@; then
+                       ret=${EXIT_OK}
+                        continue
+               fi
 
                _list="${_list} ${k}"
        done
 
        eval "${list}=\"${_list}\""
+
+       return ${ret}
 }
 
 list_sort() {
@@ -98,6 +134,12 @@ list_match() {
        return ${EXIT_ERROR}
 }
 
+list_is_empty() {
+       local list="${1}"
+
+       [ ! -n "${!list}" ]
+}
+
 list_length() {
        local length=0
 
index eb4b915678c02b075b49d0a59d2a7cc3e31570ee..fd68264d67b89bee28f2570b1add8a8f92b041be 100644 (file)
@@ -461,46 +461,87 @@ vpn_security_policies_cipher(){
        # Remove duplicated entries to proceed the list safely
        CIPHER="$(list_unique ${CIPHER})"
 
+       local ciphers_added
+       local ciphers_removed
+       local ciphers_set
+
        while [ $# -gt 0 ]; do
-               case "${1}" in
+               local arg="${1}"
+
+               case "${arg}" in
+                       +*)
+                               list_append ciphers_added "${arg:1}"
+                               ;;
                        -*)
-                               value=${1#-}
-                               # Check if the cipher is in the list of ciphers and
-                               # check if the list has after removing this cipher at least one valid value
-                               if list_match ${value} ${CIPHER}; then
-                                       list_remove CIPHER ${value}
-                               else
-                                       # We do not break here because this error does not break the processing of the next maybe valid values.
-                                       log ERROR "Can not remove ${value} from the list of Ciphers because ${value} is not in the list."
-                               fi
+                               list_append ciphers_removed "${arg:1}"
                                ;;
-                       +*)
-                               value=${1#+}
-                               # Check if the Ciphers is in the list of supported ciphers.
-                               if ! isoneof value ${!VPN_SUPPORTED_CIPHERS[@]}; then
-                                       # We do not break here because this error does not break the processing of the next maybe valid values.
-                                       log ERROR "${value} is not a supported cipher and can thats why not added to the list of ciphers."
-                               else
-                                       if list_match ${value} ${CIPHER}; then
-                                               log WARNING "${value} is already in the list of ciphers of this policy."
-                                       else
-                                               list_append CIPHER ${value}
-                                       fi
-                               fi
+                       [A-Z0-9]*)
+                               list_append ciphers_set "${arg}"
+                               ;;
+                       *)
+                               error "Invalid argument: ${arg}"
+                               return ${EXIT_ERROR}
                                ;;
                esac
                shift
        done
 
-       # Check if the list contain at least one valid cipher
-       if [ $(list_length ${CIPHER}) -ge 1 ]; then
-               if ! vpn_security_policies_write_config_key ${name} "CIPHER" ${CIPHER}; then
-                       log ERROR "The changes for the vpn security policy ${name} could not be written."
-               fi
+       # Check if the user is trying a mixed operation
+       if ! list_is_empty ciphers_set && (! list_is_empty ciphers_added || ! list_is_empty ciphers_removed); then
+               error "You cannot reset the cipher list and add or remove ciphers at the same time"
+               return ${EXIT_ERROR}
+       fi
+
+       # Set new cipher list
+       if ! list_is_empty ciphers_set; then
+               # Check if all ciphers are valid
+               local cipher
+               for cipher in ${ciphers_set}; do
+                       if ! vpn_security_policies_cipher_supported ${cipher}; then
+                               error "Unsupported cipher: ${cipher}"
+                               return ${EXIT_ERROR}
+                       fi
+               done
+
+               list_set CIPHER ${ciphers_set}
+
+       # Perform incremental updates
        else
-               log ERROR "After proceding all ciphers the list is empty and thats why no changes are written."
+               local cipher
+
+               # Perform all removals
+               for cipher in ${ciphers_removed}; do
+                       if ! list_remove CIPHER ${cipher}; then
+                               warning "${cipher} was not on the list and could not be removed"
+                       fi
+               done
+
+               for cipher in ${ciphers_added}; do
+                       if vpn_security_policies_cipher_supported ${cipher}; then
+                               if ! list_append_unique CIPHER ${cipher}; then
+                                       warning "${cipher} is already on the cipher list"
+                               fi
+                       else
+                               warning "${cipher} is unknown or unsupported and could not be added"
+                       fi
+               done
+       fi
+
+       # Check if the list contain at least one valid cipher
+       if list_is_empty CIPHER; then
+               error "Cannot save an empty cipher list"
                return ${EXIT_ERROR}
        fi
+
+       # Save everything
+       if ! vpn_security_policies_write_config_key ${name} "CIPHER" ${CIPHER}; then
+               log ERROR "The changes for the vpn security policy ${name} could not be written."
+       fi
+
+       cli_headline 1 "Current cipher list for ${name}:"
+       for cipher in ${CIPHER}; do
+               cli_print_fmt1 1 "${cipher}" "${VPN_SUPPORTED_CIPHERS[${cipher}]}"
+       done
 }
 
 # This function parses the parameters for the 'compression' command
@@ -791,6 +832,12 @@ vpn_security_policies_destroy() {
        done
 }
 
+vpn_security_policies_cipher_supported() {
+       local cipher=${1}
+
+       list_match ${cipher} ${!VPN_SUPPORTED_CIPHERS[@]}
+}
+
 vpn_security_policies_cipher_is_aead() {
        local cipher=${1}