From mboxrd@z Thu Jan 1 00:00:00 1970 From: Michael Tremer To: network@lists.ipfire.org Subject: Re: [RFC 1/2] vpn-security-policies: add new feature vpn security-policies Date: Fri, 14 Jul 2017 13:50:43 -0400 Message-ID: <1500054643.2138.1.camel@ipfire.org> In-Reply-To: <1500033869.2029.1@mail01.ipfire.org> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============6677936749232660365==" List-Id: --===============6677936749232660365== Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Hi, On Fri, 2017-07-14 at 14:04 +0200, Jonatan Schlag wrote: >=20 >=20 > Am Fr, 14. Jul, 2017 um 1:24 schrieb Michael Tremer pfire.org>: > > Hi, > >=20 > > On Thu, 2017-07-13 at 20:33 +0200, Jonatan Schlag wrote: > > =C2=A0For further explanation see: > > =C2=A0http://wiki.ipfire.org/devel/network/security-policies > > =C2=A0 > > =C2=A0Signed-off-by: Jonatan Schlag > > =C2=A0--- > > =C2=A0=C2=A0src/functions/functions.vpn-security-policies | 437 > > =C2=A0++++++++++++++++++++++++++ > > =C2=A0=C2=A01 file changed, 437 insertions(+) > > =C2=A0=C2=A0create mode 100644 src/functions/functions.vpn-security-polic= ies > > =C2=A0 > > =C2=A0diff --git a/src/functions/functions.vpn-security-policies > > =C2=A0b/src/functions/functions.vpn-security-policies > > =C2=A0new file mode 100644 > > =C2=A0index 0000000..9e24e4f > > =C2=A0--- /dev/null > > =C2=A0+++ b/src/functions/functions.vpn-security-policies > > =C2=A0@@ -0,0 +1,437 @@ > > =C2=A0+#!/bin/bash > > =C2=A0+################################################################# > > ### > > =C2=A0########### > > =C2=A0+#=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 > > =C2=A0=C2=A0=C2=A0 > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0# > > =C2=A0+# IPFire.org - A linux based > > =C2=A0firewall=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0# > > =C2=A0+# Copyright (C) 2013=C2=A0=C2=A0IPFire Network Development > > =C2=A0Team=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0# > > =C2=A0+#=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 > > =C2=A0=C2=A0=C2=A0 > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0# > >=20 > > It's 2017 :) > >=20 > > =C2=A0+# This program is free software: you can redistribute it and/or > > =C2=A0modify=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0# > > =C2=A0+# it under the terms of the GNU General Public License as > > published > > =C2=A0by=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0# > > =C2=A0+# the Free Software Foundation, either version 3 of the License, > > =C2=A0or=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0# > > =C2=A0+# (at your option) any later > > =C2=A0version.=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0# > > =C2=A0+#=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 > > =C2=A0=C2=A0=C2=A0 > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0# > > =C2=A0+# This program is distributed in the hope that it will be > > =C2=A0useful,=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0# > > =C2=A0+# but WITHOUT ANY WARRANTY; without even the implied warranty > > =C2=A0of=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0# > > =C2=A0+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.=C2=A0=C2=A0= See > > =C2=A0the=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0# > > =C2=A0+# GNU General Public License for more > > =C2=A0details.=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0# > > =C2=A0+#=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 > > =C2=A0=C2=A0=C2=A0 > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0# > > =C2=A0+# You should have received a copy of the GNU General Public > > =C2=A0License=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0# > > =C2=A0+# along with this program.=C2=A0=C2=A0If not, see > ses > > =C2=A0/>.=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0# > > =C2=A0+#=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 > > =C2=A0=C2=A0=C2=A0 > > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0# > > =C2=A0+################################################################# > > ### > > =C2=A0########### > > =C2=A0+ > > =C2=A0+VPN_SECURITY_POLICIES_CONFIG_SETTINGS=3D"CIPHER COMPRESSION > > GROUP_TYPE > > =C2=A0INTEGRITY KEY_EXCHANGE LIFETIME PFS" > > =C2=A0+VPN_SECURITY_POLICIES_READONLY=3D"system" > > =C2=A0+ > > =C2=A0+VPN_SUPPORTED_CIPHERS=3D"AES192 AES256 AES128" > > =C2=A0+VPN_SUPPORTED_INTEGRITY=3D"SHA512 SHA256 SHA128" > > =C2=A0+VPN_SUPPORTED_GROUP_TYPES=3D"MODP4096 MODP8192" > >=20 > > Obviously these need to be extended. But this will suit as a proof- > > of- > > concept. Just please order stuff alphabetically. In this case it is > > best to do it descending. > >=20 > > =C2=A0+vpn_security_policies_check_readonly() { > > =C2=A0+ # This functions checks if a policy is readonly > > =C2=A0+ # returns true when yes and false when no > > =C2=A0+ > > =C2=A0+ if isoneof name ${VPN_SECURITY_POLICIES_READONLY}; then > > =C2=A0+ return ${EXIT_TRUE} > > =C2=A0+ else > > =C2=A0+ return ${EXIT_FALSE} > > =C2=A0+ fi > > =C2=A0+} > >=20 > > Ok. > >=20 > > =C2=A0+vpn_security_policies_write_config() { > > =C2=A0+ # This function writes all values to a via ${name} > > =C2=A0specificated vpn security policy configuration file > > =C2=A0+ assert [ $# -ge 1 ] > > =C2=A0+ > > =C2=A0+ local name=3D"${1}" > > =C2=A0+ > > =C2=A0+ if ! vpn_security_policy_exists ${name}; then > > =C2=A0+ log ERROR "No such policy: ${name}" > > =C2=A0+ return ${EXIT_ERROR} > > =C2=A0+ fi > >=20 > > I think you need to improve some of the error messages. A sentence > > is > > usually good. The shorter the sweeter. Not sure if "no such policy" > > is > > helpful when they are actually called security policies. So, don't > > go > > too short. > >=20 > > =C2=A0+ > > =C2=A0+ if vpn_security_policies_check_readonly ${name}; then > > =C2=A0+ log ERROR "${name} is a readable only vpn > > security > > =C2=A0policy" > > =C2=A0+ return ${EXIT_ERROR} > > =C2=A0+ fi > >=20 > > Here I would suggest: "The system security policy cannot be > > changed" > >=20 > > =C2=A0+ > > =C2=A0+ local args > > =C2=A0+ list_append args ${VPN_SECURITY_POLICIES_CONFIG_SETTINGS} > >=20 > > No need to call list_append here. Settings args to > > VPN_SECURITY_POLICIES_CONFIG_SETTINGS is enough. You just just pass > > it > > to settings_write without using $args. > >=20 > > =C2=A0+ > > =C2=A0+ local path=3D"$(vpn_security_policies_path ${name})" > > =C2=A0+ if [ ! -w ${path} ]; then > > =C2=A0+ log ERROR "${path} is not writeable" > > =C2=A0+ return ${EXIT_ERROR} > > =C2=A0+ fi > > =C2=A0+ > > =C2=A0+ settings_write "${path}" ${args} > > =C2=A0+ # TODO everytime we successfully write a config we should > > =C2=A0call some trigger to take the changes into effect > > =C2=A0+} > >=20 > > Space between the settings_write and comments, please. > >=20 > > What happens when the settings could not be written? > >=20 > > =C2=A0+vpn_security_policies_write_config_key() { > > =C2=A0+ # This funtion writes the value for one key to a via > > ${name} > > =C2=A0specificated vpn security policy configuration file > > =C2=A0+ assert [ $# -ge 3 ] > > =C2=A0+ local name=3D${1} > > =C2=A0+ > > =C2=A0+ if ! vpn_security_policy_exists ${name}; then > > =C2=A0+ log ERROR "No such policy: ${name}" > > =C2=A0+ return ${EXIT_ERROR} > > =C2=A0+ fi > > =C2=A0+ > > =C2=A0+ local key=3D${2} > > =C2=A0+ shift 2 > > =C2=A0+ local value=3D"$@" > > =C2=A0+ log DEBUG "Set '${key}' to new value '${value}'" > >=20 > > Please group the argument parsing together at the top and then test > > if > > the policy exists. This is hard to read. > >=20 > > Also the logging message is a bit random since it doesn't mention > > the > > security policy here. > >=20 > > =C2=A0+ # Read the config settings > > =C2=A0+ if ! vpn_security_policies_read_config ${name}; then > > =C2=A0+ return ${EXIT_ERROR} > > =C2=A0+ fi > >=20 > > This will overwrite any global variables. So you will need to > > call > >=20 > > =C2=A0 local VPN_SECURITY_POLICIES_CONFIG_SETTINGS > >=20 > > before you read the settings from file. > >=20 > > =C2=A0+ # Set the key to a new value > > =C2=A0+ eval "${key}=3D\"${value}\"" > >=20 > > Never ever use eval. This will allow someone to pass shell commands > > that may get executed. At no time ever we would want that. >=20 > I was aware of the problems eval can result, but we use it at some > other functions, so I thought i would be ok. > Anyway already changed. >=20 > > There is a function called assign() that takes care of assigning a > > variable. > >=20 > > =C2=A0+ if ! vpn_security_policies_write_config ${name}; then > > =C2=A0+ return ${EXIT_ERROR} > > =C2=A0+ fi > > =C2=A0+ > > =C2=A0+ return ${EXIT_TRUE} > > =C2=A0+ > > =C2=A0+} > > =C2=A0+ > > =C2=A0+vpn_security_policies_read_config() { > > =C2=A0+ # Reads one or more keys out of a settings file or all if > > no > > =C2=A0key is provided. > > =C2=A0+ assert [ $# -ge 1 ] > > =C2=A0+ > > =C2=A0+ local name=3D"${1}" > > =C2=A0+ shift 1 > > =C2=A0+ > > =C2=A0+ if ! vpn_security_policy_exists ${name}; then > > =C2=A0+ log ERROR "No such policy: ${name}" > > =C2=A0+ return ${EXIT_ERROR} > > =C2=A0+ fi > > =C2=A0+ > > =C2=A0+ > > =C2=A0+ local args > > =C2=A0+ if [ $# -eq 0 ] && [ -n > > =C2=A0"${VPN_SECURITY_POLICIES_CONFIG_SETTINGS}" ]; then > > =C2=A0+ list_append args > > =C2=A0${VPN_SECURITY_POLICIES_CONFIG_SETTINGS} > > =C2=A0+ else > > =C2=A0+ list_append args $@ > > =C2=A0+ fi > > =C2=A0+ > > =C2=A0+ local path=3D"$(vpn_security_policies_path ${name})" > > =C2=A0+ if [ ! -r ${path} ]; then > > =C2=A0+ log ERROR "${path} is not readable" > > =C2=A0+ return ${EXIT_ERROR} > > =C2=A0+ fi > >=20 > > Why do you need to do this every time? Doesn't settings_read do > > this? > >=20 > > =C2=A0+ > > =C2=A0+ settings_read "${path}" ${args} > > =C2=A0+} > > =C2=A0+ > > =C2=A0+vpn_security_policies_path() { > > =C2=A0+ # Returns the path to a the configuration fora given name > > =C2=A0+ assert [ $# -eq 1 ] > > =C2=A0+ local name=3D${1} > > =C2=A0+ > > =C2=A0+ if vpn_security_policies_check_readonly ${name}; then > > =C2=A0+ echo "/usr/share/network/vpn/security- > > =C2=A0policies/${name}" > > =C2=A0+ else > > =C2=A0+ echo "/etc/network/vpn/security-policies/${name}" > > =C2=A0+ fi > > =C2=A0+} > >=20 > > Hard-coded paths :( > >=20 > > =C2=A0+ > > =C2=A0+vpn_security_policies_show() { > > =C2=A0+ # Print the content of a vpn security policy > > configuration > > =C2=A0file in a nice way > > =C2=A0+ assert [ $# -eq 1 ] > > =C2=A0+ local name=3D${1} > >=20 > > Here you will need to do the local variable initialization before > > you > > red this in - as above. > >=20 > > =C2=A0+ # Break if read fails > > =C2=A0+ if ! vpn_security_policies_read_config ${name}; then > > =C2=A0+ return ${EXIT_ERROR} > > =C2=A0+ fi > > =C2=A0+ > > =C2=A0+ cli_print_fmt1 0 "Security Policy: ${name}" > > =C2=A0+ cli_space > > =C2=A0+ > > =C2=A0+ # This could be done in a loop but a loop is much more > > =C2=A0complicated > > =C2=A0+ # because we print 'Group Types' but the variable is > > named > > =C2=A0'GROUP_TYPES' > > =C2=A0+ cli_print_fmt1 1 "Ciphers:" > > =C2=A0+ cli_print_fmt1 2 "${CIPHER}" > > =C2=A0+ cli_space > >=20 > > This does not show any broken ciphers as broken. But we could add > > this > > later as well. This patch is quite huge already. > >=20 > > =C2=A0+ cli_print_fmt1 1 "Integrity:" > > =C2=A0+ cli_print_fmt1 2 "${INTEGRITY}" > > =C2=A0+ cli_space > > =C2=A0+ cli_print_fmt1 1 "Group Types:" > > =C2=A0+ cli_print_fmt1 2 "${GROUP_TYPE}" > > =C2=A0+ cli_space > > =C2=A0+ > > =C2=A0+ cli_print_fmt1 1 "Key exchange:" "${KEY_EXCHANGE}" > >=20 > > Capital E in Exchange > >=20 > > =C2=A0+ cli_print_fmt1 1 "Key Lifetime in seconds:" "${LIFETIME}" > >=20 > > The lifetime should be formatted nicely because seconds are hard to > > understand. There is a function that formats these nicely. > >=20 > > =C2=A0+ if enabled PFS; then > > =C2=A0+ cli_print_fmt1 1 "Perfect Forward Secrecy:" > > =C2=A0"enabled" > > =C2=A0+ else > > =C2=A0+ cli_print_fmt1 1 "Perfect Forward Secrecy:" > > =C2=A0"disabled" > > =C2=A0+ fi > > =C2=A0+ cli_space > > =C2=A0+ if enabled COMPRESSION; then > > =C2=A0+ cli_print_fmt1 1 "Compression:" "enabled" > > =C2=A0+ else > > =C2=A0+ cli_print_fmt1 1 "Compression:" "disabled" > > =C2=A0+ fi > > =C2=A0+ cli_space > > =C2=A0+} > > =C2=A0+ > > =C2=A0+vpn_security_policy_exists() { > > =C2=A0+ # This function checks if a vpn security policy exists > > =C2=A0+ # Returns True when yes and false when not > > =C2=A0+ assert [ $# -eq 1 ] > > =C2=A0+ local name=3D${1} > > =C2=A0+ > > =C2=A0+ local path=3D$(vpn_security_policies_path ${name}) > > =C2=A0+ [ -f ${path} ] > > =C2=A0+} > > =C2=A0+ > > =C2=A0+ > > =C2=A0+vpn_security_policies_cipher(){ > > =C2=A0+ # This function parses the parameters for the 'cipher' > > =C2=A0command > > =C2=A0+ local name=3D${1} > > =C2=A0+ shift > > =C2=A0+ > > =C2=A0+ if [ $# -eq 0 ]; then > > =C2=A0+ log ERROR "You must pass at least one value after > > =C2=A0cipher" > > =C2=A0+ return ${EXIT_ERROR} > > =C2=A0+ fi > > =C2=A0+ > >=20 > > local CIPHER > >=20 > > =C2=A0+ if ! vpn_security_policies_read_config ${name} "CIPHER"; > > =C2=A0then > > =C2=A0+ return ${EXIT_ERROR} > > =C2=A0+ fi > > =C2=A0+ > > =C2=A0+ # Remove duplicated entries to proceed the list safely > > =C2=A0+ CIPHER=3D"$(list_unique ${CIPHER})" > > =C2=A0+ > > =C2=A0+ while [ $# -gt 0 ]; do > > =C2=A0+ case "${1}" in > > =C2=A0+ -*) > > =C2=A0+ value=3D${1#-} > > =C2=A0+ # Check if the cipher is in the > > list > > =C2=A0of ciphers and > > =C2=A0+ # check if the list has after > > =C2=A0removing this cipher at least one valid value > > =C2=A0+ if list_match ${value} ${CIPHER} > > && > > =C2=A0[ $(list_length ${CIPHER}) -gt 1 ]; then > > =C2=A0+ list_remove CIPHER > > ${value} > > =C2=A0+ else > > =C2=A0+ log ERROR "Can not remove > > =C2=A0${value} from the list of Ciphers because ${value} is not in the > > list > > =C2=A0or the list would be empty after removing this cipher" > > =C2=A0+ fi > >=20 > > There is no return here which ends the function on this error. > >=20 > > I think you should check this after the loop to support things > > like: > >=20 > > -3DES +AES256 > >=20 > > This would crash if 3DES is the last cipher but the user does not > > intend to remove all ciphers. > >=20 > > =C2=A0+ ;; > > =C2=A0+ +*) > > =C2=A0+ value=3D${1#+} > > =C2=A0+ # Check if the Ciphers is in the > > =C2=A0list of supported ciphers. > > =C2=A0+ if ! isoneof value > > =C2=A0${VPN_SUPPORTED_CIPHERS}; then > > =C2=A0+ log ERROR "${value} is > > not a > > =C2=A0supported cipher and can thats why not added to the list of > > ciphers" > > =C2=A0+ else > > =C2=A0+ if list_match ${value} > > =C2=A0${CIPHER}; then > > =C2=A0+ log WARNING > > =C2=A0"${value} is already in the list of ciphers of this policy" > > =C2=A0+ else > > =C2=A0+ list_append > > CIPHER > > =C2=A0${value} > > =C2=A0+ fi > > =C2=A0+ fi > > =C2=A0+ ;; > > =C2=A0+ esac > > =C2=A0+ shift > > =C2=A0+ done > > =C2=A0+ > > =C2=A0+ vpn_security_policies_write_config_key ${name} "CIPHER" > > =C2=A0${CIPHER} > >=20 > > Are there no errors to catch here? > >=20 > > =C2=A0+} > > =C2=A0+ > > =C2=A0+vpn_security_policies_compression(){ > > =C2=A0+ # This function parses the parameters for the > > 'compression' > > =C2=A0command > > =C2=A0+ local name=3D${1} > > =C2=A0+ local value=3D${2} > > =C2=A0+ # Check if we get only one argument after compression > > > > =C2=A0+ if [ ! $# -eq 2 ] || ! isbool value; then > > =C2=A0+ log ERROR "You can pass only one parameter after > > =C2=A0compression and this one must be 'on' or 'off'" > > =C2=A0+ return ${EXIT_ERROR} > > =C2=A0+ fi > >=20 > > Probably not the nicest handling in case of no argument or so. This > > also suggests two values but actually more would be accepted as > > well. >=20 > I added a comment but just for clarification, sure more values are > allowed. But I see no sense in print 1 0 on off true false yes no, > because it does not make things more clear it makes them even worse. > From my point of view on and off are the most understandable phrases, > so I print just this two but other will works too. >=20 > And something like "All boolean values are accepted" is too implicit. No, that is not better to show all possible values. But what could help is saying what is not possible. For example: "Invalid argument" > > =C2=A0+ > > =C2=A0+ vpn_security_policies_write_config_key "${name}" > > =C2=A0"COMPRESSION" "${value}" > > =C2=A0+} > > =C2=A0+ > > =C2=A0+vpn_security_policies_group_type(){ > > =C2=A0+ # This function parses the parameters for the 'group- > > type' > > =C2=A0command. > > =C2=A0+ local name=3D${1} > > =C2=A0+ shift > > =C2=A0+ > > =C2=A0+ if [ $# -eq 0 ]; then > > =C2=A0+ log ERROR "You must pass at least one value after > > =C2=A0group-type" > > =C2=A0+ return ${EXIT_ERROR} > > =C2=A0+ fi > > =C2=A0+ > > =C2=A0+ if ! vpn_security_policies_read_config ${name} > > "GROUP_TYPE"; > > =C2=A0then > > =C2=A0+ return ${EXIT_ERROR} > > =C2=A0+ fi > > =C2=A0+ > > =C2=A0+ # Remove duplicated entries to proceed the list safely > > =C2=A0+ GROUP_TYPE=3D"$(list_unique ${GROUP_TYPE})" > > =C2=A0+ > > =C2=A0+ while [ $# -gt 0 ]; do > > =C2=A0+ case "${1}" in > > =C2=A0+ -*) > > =C2=A0+ value=3D${1#-} > > =C2=A0+ # Check if the group type is in > > the > > =C2=A0list of group types and > > =C2=A0+ # check if the list has after > > =C2=A0removing this group type at leatst one valid value > > =C2=A0+ if list_match ${value} > > ${GROUP_TYPE} > > =C2=A0&& [ $(list_length ${GROUP_TYPE}) -gt 1 ]; then > > =C2=A0+ list_remove GROUP_TYPE > > =C2=A0${value} > > =C2=A0+ else > > =C2=A0+ log ERROR "Can not remove > > =C2=A0${value} from the list of group types because ${value} is not in > > the > > =C2=A0list or the list would be empty after removing this group type" > > =C2=A0+ fi > > =C2=A0+ ;; > > =C2=A0+ +*) > > =C2=A0+ value=3D${1#+} > > =C2=A0+ # Check if the group type is in > > the > > =C2=A0list of supported group types. > > =C2=A0+ if ! isoneof value > > =C2=A0${VPN_SUPPORTED_GROUP_TYPES}; then > > =C2=A0+ log ERROR "${value} is > > not a > > =C2=A0supported group type and can thats why not added to the list of > > group > > =C2=A0types" > > =C2=A0+ else > > =C2=A0+ if list_match ${value} > > =C2=A0${GROUP_TYPE}; then > > =C2=A0+ log WARNING > > =C2=A0"${value} is already in the list of group-types of this policy" > > =C2=A0+ else > > =C2=A0+ list_append > > =C2=A0GROUP_TYPES ${value} > > =C2=A0+ fi > > =C2=A0+ fi > > =C2=A0+ ;; > > =C2=A0+ esac > > =C2=A0+ shift > > =C2=A0+ done > > =C2=A0+ > > =C2=A0+ vpn_security_policies_write_config_key ${name} > > "GROUP_TYPE" > > =C2=A0${GROUP_TYPE} > > =C2=A0+} > >=20 > > Same as above. > >=20 > > =C2=A0+ > > =C2=A0+vpn_security_policies_integrity(){ > > =C2=A0+ # This function parses the parameters for the 'integrity' > > =C2=A0command > > =C2=A0+ local name=3D${1} > > =C2=A0+ shift > > =C2=A0+ > > =C2=A0+ if [ $# -eq 0 ]; then > > =C2=A0+ log ERROR "You must pass at least one value after > > =C2=A0integrity" > > =C2=A0+ return ${EXIT_ERROR} > > =C2=A0+ fi > > =C2=A0+ > > =C2=A0+ if ! vpn_security_policies_read_config ${name} > > "INTEGRITY"; > > =C2=A0then > > =C2=A0+ return ${EXIT_ERROR} > > =C2=A0+ fi > > =C2=A0+ > > =C2=A0+ # Remove duplicated entries to proceed the list safely > > =C2=A0+ INTEGRITY=3D"$(list_unique ${INTEGRITY})" > > =C2=A0+ > > =C2=A0+ while [ $# -gt 0 ]; do > > =C2=A0+ case "${1}" in > > =C2=A0+ -*) > > =C2=A0+ value=3D${1#-} > > =C2=A0+ # Check if the integrity hash is > > in > > =C2=A0the list of integrity hashes and > > =C2=A0+ # check if the list has after > > =C2=A0removing this=C2=A0=C2=A0integrity hash at least one valid value > > =C2=A0+ if list_match ${value} > > ${INTEGRITY} > > =C2=A0&& [ $(list_length ${INTEGRITY}) -gt 1 ]; then > > =C2=A0+ list_remove INTEGRITY > > =C2=A0${value} > > =C2=A0+ else > > =C2=A0+ log ERROR "Can not remove > > =C2=A0${value} from the list of integrity hashes because ${value} is not > > in > > =C2=A0the list or the list would be empty after removing this integrity > > =C2=A0hash" > > =C2=A0+ fi > > =C2=A0+ ;; > > =C2=A0+ +*) > > =C2=A0+ value=3D${1#+} > > =C2=A0+ # Check if the Ciphers is in the > > =C2=A0list of supported integrity hashes. > > =C2=A0+ if ! isoneof value > > =C2=A0${VPN_SUPPORTED_INTEGRITY}; then > > =C2=A0+ log ERROR "${value} is > > not a > > =C2=A0supported integrity hashes and can thats why not added to the list > > of > > =C2=A0integrity hashes" > > =C2=A0+ else > > =C2=A0+ if list_match ${value} > > =C2=A0${INTEGRITY}; then > > =C2=A0+ log WARNING > > =C2=A0"${value} is already in the list of integrety hashes of this > > policy" > > =C2=A0+ else > > =C2=A0+ list_append > > =C2=A0INTEGRITY ${value} > > =C2=A0+ fi > > =C2=A0+ fi > > =C2=A0+ ;; > > =C2=A0+ esac > > =C2=A0+ shift > > =C2=A0+ done > > =C2=A0+ > > =C2=A0+ vpn_security_policies_write_config_key ${name} > > "INTEGRITY" > > =C2=A0${INTEGRITY} > > =C2=A0+} > >=20 > > Likewise. > >=20 > > =C2=A0+ > > =C2=A0+vpn_security_policies_key_exchange() { > > =C2=A0+ # This function parses the parameters for the 'key- > > exchange'=C2=A0 > > =C2=A0command > > =C2=A0+ local name=3D${1} > > =C2=A0+ local value=3D${2} > > =C2=A0+ # Check if we get only one argument after compression > > > > =C2=A0+ if [ ! $# -eq 2 ] || ! isoneof value "ikev1" "ikev2"; > > then > > =C2=A0+ log ERROR "You can pass only one parameter after > > =C2=A0key-exchange and this one must be 'ikev1' or 'ikev2'" > > =C2=A0+ return ${EXIT_ERROR} > > =C2=A0+ fi > >=20 > > Should we accept values like "IKEv2", too? > >=20 > > =C2=A0+ > > =C2=A0+ vpn_security_policies_write_config_key "${name}" > > =C2=A0"KEY_EXCHANGE" "${value}" > > =C2=A0+} > > =C2=A0+ > > =C2=A0+vpn_security_policies_lifetime(){ > > =C2=A0+ # This function parses the parameters for the 'lifetime' > > =C2=A0command > > =C2=A0+ local name=3D${1} > > =C2=A0+ local value=3D${2} > > =C2=A0+ # Check if we get only one argument after compression > > > > =C2=A0+ if [ ! $# -eq 2 ] || ! isinteger value || [ ${value} -le > > 0 > > =C2=A0]; then > > =C2=A0+ log ERROR "You can pass only one parameter after > > =C2=A0liftime and this one must be an valid integer greater zero" > > =C2=A0+ return ${EXIT_ERROR} > > =C2=A0+ fi > > =C2=A0+ > > =C2=A0+ vpn_security_policies_write_config_key "${name}" > > "LIFETIME" > > =C2=A0"${value}" > > =C2=A0+} > >=20 > > This one should accept values like "1h". There is a function for > > it. > >=20 > > =C2=A0+ > > =C2=A0+vpn_security_policies_pfs(){ > > =C2=A0+ # This function parses the parameters for the 'pfs' > > command > > =C2=A0+ local name=3D${1} > > =C2=A0+ local value=3D${2} > > =C2=A0+ # Check if we get only one argument after compression > > > > =C2=A0+ if [ ! $# -eq 2 ] || ! isbool value; then > > =C2=A0+ log ERROR "You can pass only one parameter after > > pfs > > =C2=A0and this one must be 'on' or 'off'" > > =C2=A0+ return ${EXIT_ERROR} > > =C2=A0+ fi > > =C2=A0+ > > =C2=A0+ vpn_security_policies_write_config_key "${name}" "PFS" > > =C2=A0"${value}" > > =C2=A0+} > >=20 > > See above. > >=20 > > =C2=A0+ > > =C2=A0+vpn_security_policies_check_name() { > > =C2=A0+ # This function checks if a vpn security policy name is > > =C2=A0valid > > =C2=A0+ # Allowed are only A-Za-z0-9 > > =C2=A0+ assert [ $# -eq 1 ] > > =C2=A0+ local name=3D${1} > > =C2=A0+ [[ ${name} =3D~ [[:alnum:]] ]] > >=20 > > This only checks if there is at least one alphanumerical character > > in > > the string. But it does not exclusively check for them I think. > >=20 > > =C2=A0+} > > =C2=A0+ > > =C2=A0+vpn_security_policies_new() { > > =C2=A0+ # Function that creates based on the paramters one ore > > more > > =C2=A0new vpn security policies > > =C2=A0+ local name > > =C2=A0+ for name in $@; do > > =C2=A0+ if vpn_security_policy_exists ${name}; then > > =C2=A0+ log ERROR "The vpn security policy > > ${name} > > =C2=A0does already exist" > > =C2=A0+ continue > > =C2=A0+ fi > > =C2=A0+ > > =C2=A0+ if vpn_security_policies_check_name ${name}; then > > =C2=A0+ log ERROR "'${name}' contains illegal > > =C2=A0characters. Allowed are only A-Za-z0-9 are allowed" > > =C2=A0+ continue > > =C2=A0+ fi > > =C2=A0+ > > =C2=A0+ log DEBUG "Creating vpn security policy ${name}" > > =C2=A0+ cp "$(vpn_security_policies_path "system")" > > =C2=A0"$(vpn_security_policies_path ${name})" > >=20 > > Don't use cp. >=20 > Why not not and what would be a better solution? Just read the stuff and then write it again using the shell. That avoids forking the cp process. The other reason is that cp is not very predictable sometimes. If a directory exists for the target, it would then place the file into that directory. That is not what we want. You could maybe write a function called copy() in the util functions file that looks like this: copy() { local src=3D${1} local dst=3D${2} local data=3D$(fread ${src}) fwrite ${dst} "${data}" } Obviously this is not smart for gigabytes of data, but this is good enough to copy a configuration file of a few kilobytes. Best, -Michael >=20 > Best, > Jonatan >=20 > >=20 > > =C2=A0+ done > > =C2=A0+ > > =C2=A0+} > >=20 > > What happens when I create a new policy called "system"? > >=20 > > =C2=A0+ > > =C2=A0+vpn_security_policies_destroy() { > > =C2=A0+ # Function that deletes based on the passed parameters > > one > > =C2=A0ore more vpn security policies > > =C2=A0+ local name > > =C2=A0+ for name in $@; do > > =C2=A0+ if ! vpn_security_policy_exists ${name}; then > > =C2=A0+ log ERROR "The vpn security policy > > ${name} > > =C2=A0does not exist" > > =C2=A0+ continue > > =C2=A0+ fi > > =C2=A0+ > > =C2=A0+ if vpn_security_policies_check_readonly ${name}; > > =C2=A0then > > =C2=A0+ log ERROR "The vpn security policy > > ${name} > > =C2=A0is readonly and can thats why not deleted" > > =C2=A0+ continue > > =C2=A0+ fi > > =C2=A0+ > > =C2=A0+ log DEBUG "Deleting vpn security policy ${name}" > > =C2=A0+ rm -f $(vpn_security_policies_path ${name}) > > =C2=A0+ done > > =C2=A0+} > >=20 > > This is overall good work. See the comments above and go through > > them > > one by one and please send an updated version of the patch when > > ever > > you are ready. > >=20 > > Best, > > -Michael > >=20 > >=20 > >=20 --===============6677936749232660365== Content-Type: application/pgp-signature Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="signature.asc" MIME-Version: 1.0 LS0tLS1CRUdJTiBQR1AgU0lHTkFUVVJFLS0tLS0KVmVyc2lvbjogR251UEcgdjIKCmlRSWNCQUFC Q2dBR0JRSlphUVIwQUFvSkVJQjU4UDl2a0FrSHpLc1AvMkh2YzdPc0dlamJucHZXeWRxWE95QWcK N1k3N3VDVVRhbGlMN0xoU241bWZ2NjRsbWZ4bHM2a2hPVVBHU2w5YUVncVk0T25jQ1lPMjNyRTdZ SXU2ZWJhbAo2QmEzWTMzOXEzTUhGV3orN1Q5M2NaRkpNS3pBZVlJeWdLSVAwMWpFeXR2NmRwaGNm UytKRFl2SHBiMXhkOEliCkxlbHBFK2lMcHdTbjVQUTlVaFlZa3VsdTZPSlBYRzU4Ty80TEh1Z3hk VmFkQUM0OENPNG5xL2FPUGRmNzYxU1AKcVZ4QXhlS3dJUVRDS3ROcmw1cnZpdlBoOFhrL0wra3hq SHgrV2tzUXg1V2h6ZUV5WkN4d3N3WmJSVllIVmphVwoxQ1pJMUpqL05YNXZyZEtYU1V4aEhHNVNY Vjl2NWFUMDViYURJSFB3Y3VwVmpOemhFbnBuVDBybVNsWlpHNTVKCjJqdXRiYktFQUFjeXIvZlN3 c3p1Y2ZXSCtOcVdxSk9IU0xLeXZFUXpXbmhXdmZ2aFBrRzRodlg0MVdud3NCYnEKNXRMRXhxK2wz aHZSOXVnemJiUXdlWHEvWGRWN2tjSmM4TUpSUkJHVDZhRWlFYWR4ak41WjhQeDVCcEZQYUtKVwpx WUlhRmthdWQ5N1dUZlR6WjkwMmR3NEEzcnhnam5kWGRuYndFcmtJamNNZ2lJQjZWM1d5b1ZIOGdF RGt2MVhVCnlZaURoVjNuUklaZTBmSmRrN3VhVCtFVUh6UUxsZjA3TU5VN2FzekFGbFBTTUQxUTdB V2gyS2ZCbHdIMHlleGIKUFRsTjF0cmJ0NUllTFQwbDByQUpwaGVWMDg2UGhHWlF3THpuVDBHVkJq TzJvdFVmRzFjaWg2dEpRTkFNZllXaApzb3NLMW5VVHBKRUNGc2hhWEV0cAo9OW5UWAotLS0tLUVO RCBQR1AgU0lHTkFUVVJFLS0tLS0K --===============6677936749232660365==--