From c060ecccb2c25e3ff01e82de963510cdf1c614ef Mon Sep 17 00:00:00 2001 From: Johannes Meixner Date: Tue, 9 Apr 2024 13:41:35 +0200 Subject: [PATCH 01/10] New global function get_var_from_file() In lib/global-functions.sh added new function get_var_from_file() see https://github.com/rear/rear/pull/3171 --- usr/share/rear/lib/global-functions.sh | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/usr/share/rear/lib/global-functions.sh b/usr/share/rear/lib/global-functions.sh index 77263cb1d6..3efe9a6de4 100644 --- a/usr/share/rear/lib/global-functions.sh +++ b/usr/share/rear/lib/global-functions.sh @@ -14,6 +14,42 @@ function read_and_strip_file () { sed -e '/^[[:space:]]/d;/^$/d;/^#/d' "$filename" } +# Get the value of a non-array variable that is set in a file. +# The get_var_from_file function is meant to be used with files +# like /etc/os-release or certain files in /etc/sysconfig or /etc/default +# that basically only do shell-compatible variable assignments (VAR="value") +# but get_var_from_file is not meant to be used with arbitrary shell scripts +# because commands in the file are executed via 'source' so any effects of +# executing those commands will happen like changing things in the system. +# Zero return code means the variable was set in the file and then +# stdout is the value of the variable (could be empty or blank). +# Non-zero return code in all other cases. +# Usage example: +# if my_var="$( get_var_from_file FILE_NAME VAR_NAME )" ; then +# # Code when VAR_NAME was set in FILE_NAME +# ... +# else +# # Code when the value of VAR_NAME is unknown +# ... +# fi +function get_var_from_file() { + # The first argument $1 is the file name. + # The second argument $2 is the name of the variable. + # Via 'bash -c' $0 in that bash is set to the first argument so $0 in that bash is the file name + # and $1 in that bash is set to the second argument so $1 in that bash is the name of the variable. + # The inital "unset $1 || exit 1" ensures that the variable can be set in the file + # in particular it exits if the variable is readonly within that 'bash -c' + # e.g. "get_var_from_file some_file UID" results non-zero return code. + # The "set -u" after the file was sourced lets the subsequent access of the variable "${!1}" + # exit with non-zero return code when the variable was not set in the file. + # The 'source' return code is ignored because 'source' returns the status of the last sourced command + # but we are not interested in the the status of the last command in the file but only whether or not + # the variable was set in the file (it could be also set to an empty or blank value). + # For details about the reasons behind the get_var_from_file implementation see + # https://github.com/rear/rear/pull/3171 + bash -c 'unset $1 || exit 1 ; source "$0" >/dev/null ; set -u ; echo "${!1}"' "$1" "$2" || return 1 +} + # Three functions to test # if the argument is an integer # if the argument is a positive integer (i.e. test for '> 0') From ef14f5f382147d67af76210a8b0d8f957df0f037 Mon Sep 17 00:00:00 2001 From: Johannes Meixner Date: Tue, 9 Apr 2024 14:07:21 +0200 Subject: [PATCH 02/10] Update global-functions.sh Dropped the final '|| return 1' from the get_var_from_file() implementation, see https://github.com/rear/rear/pull/3203#issuecomment-2044979689 --- usr/share/rear/lib/global-functions.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/share/rear/lib/global-functions.sh b/usr/share/rear/lib/global-functions.sh index 3efe9a6de4..4e0c7f21be 100644 --- a/usr/share/rear/lib/global-functions.sh +++ b/usr/share/rear/lib/global-functions.sh @@ -47,7 +47,7 @@ function get_var_from_file() { # the variable was set in the file (it could be also set to an empty or blank value). # For details about the reasons behind the get_var_from_file implementation see # https://github.com/rear/rear/pull/3171 - bash -c 'unset $1 || exit 1 ; source "$0" >/dev/null ; set -u ; echo "${!1}"' "$1" "$2" || return 1 + bash -c 'unset $1 || exit 1 ; source "$0" >/dev/null ; set -u ; echo "${!1}"' "$1" "$2" } # Three functions to test From 0dfc2a80a6231859dd8bfcd64eece71e0069c82e Mon Sep 17 00:00:00 2001 From: Johannes Meixner Date: Thu, 11 Apr 2024 12:06:11 +0200 Subject: [PATCH 03/10] Update global-functions.sh Explain why we source the file in a separated shell and why stdout of the sourced file must be discarded and add specific URLs to pull request comments that show our resoning behind --- usr/share/rear/lib/global-functions.sh | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/usr/share/rear/lib/global-functions.sh b/usr/share/rear/lib/global-functions.sh index 4e0c7f21be..e99e0f78b4 100644 --- a/usr/share/rear/lib/global-functions.sh +++ b/usr/share/rear/lib/global-functions.sh @@ -35,14 +35,26 @@ function read_and_strip_file () { function get_var_from_file() { # The first argument $1 is the file name. # The second argument $2 is the name of the variable. + # We source the file in a separated shell to avoid failures when the variable is readonly in the current shell + # so the variable cannot be set in the current shell or in a subshell (a subshell interits 'readonly') + # (see https://github.com/rear/rear/pull/3171#discussion_r1521750947) + # and to avoid failures when any other variable that is set in the file is readonly in the current shell + # because sourcing a file where a readonly variable is set causes a panic abort of 'source' at that place + # when sourcing in a subshell i.e. when get_var_from_file is called as in the above usage example + # (see https://github.com/rear/rear/pull/3165#discussion_r1505473662 + # and https://github.com/rear/rear/pull/3165#discussion_r1505520542). # Via 'bash -c' $0 in that bash is set to the first argument so $0 in that bash is the file name # and $1 in that bash is set to the second argument so $1 in that bash is the name of the variable. # The inital "unset $1 || exit 1" ensures that the variable can be set in the file # in particular it exits if the variable is readonly within that 'bash -c' - # e.g. "get_var_from_file some_file UID" results non-zero return code. + # e.g. "get_var_from_file some_file UID" results non-zero return code + # (see https://github.com/rear/rear/pull/3171#issuecomment-2022625255). # The "set -u" after the file was sourced lets the subsequent access of the variable "${!1}" # exit with non-zero return code when the variable was not set in the file. + # The 'source' stdout must be discarded because the get_var_from_file stdout must be only the variable value + # (see https://github.com/rear/rear/pull/3171#issuecomment-2018002598). # The 'source' return code is ignored because 'source' returns the status of the last sourced command + # (see https://github.com/rear/rear/pull/3171#issuecomment-2019531750). # but we are not interested in the the status of the last command in the file but only whether or not # the variable was set in the file (it could be also set to an empty or blank value). # For details about the reasons behind the get_var_from_file implementation see From 853d65daee67d673f431897f76aee4f75dc9e3c8 Mon Sep 17 00:00:00 2001 From: Johannes Meixner Date: Thu, 11 Apr 2024 12:09:51 +0200 Subject: [PATCH 04/10] Update global-functions.sh Typo fix "the the" -> "the" --- usr/share/rear/lib/global-functions.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/share/rear/lib/global-functions.sh b/usr/share/rear/lib/global-functions.sh index e99e0f78b4..1d42b1016b 100644 --- a/usr/share/rear/lib/global-functions.sh +++ b/usr/share/rear/lib/global-functions.sh @@ -55,7 +55,7 @@ function get_var_from_file() { # (see https://github.com/rear/rear/pull/3171#issuecomment-2018002598). # The 'source' return code is ignored because 'source' returns the status of the last sourced command # (see https://github.com/rear/rear/pull/3171#issuecomment-2019531750). - # but we are not interested in the the status of the last command in the file but only whether or not + # but we are not interested in the status of the last command in the file but only whether or not # the variable was set in the file (it could be also set to an empty or blank value). # For details about the reasons behind the get_var_from_file implementation see # https://github.com/rear/rear/pull/3171 From 80c8652abf596f1ae56b4ecaa4ff37ce19eea04c Mon Sep 17 00:00:00 2001 From: Johannes Meixner Date: Thu, 11 Apr 2024 12:20:31 +0200 Subject: [PATCH 05/10] Update global-functions.sh Typo fix in comment: Removed false full stop '.' because the sentence does not end there. --- usr/share/rear/lib/global-functions.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/share/rear/lib/global-functions.sh b/usr/share/rear/lib/global-functions.sh index 1d42b1016b..30df54df14 100644 --- a/usr/share/rear/lib/global-functions.sh +++ b/usr/share/rear/lib/global-functions.sh @@ -54,7 +54,7 @@ function get_var_from_file() { # The 'source' stdout must be discarded because the get_var_from_file stdout must be only the variable value # (see https://github.com/rear/rear/pull/3171#issuecomment-2018002598). # The 'source' return code is ignored because 'source' returns the status of the last sourced command - # (see https://github.com/rear/rear/pull/3171#issuecomment-2019531750). + # (see https://github.com/rear/rear/pull/3171#issuecomment-2019531750) # but we are not interested in the status of the last command in the file but only whether or not # the variable was set in the file (it could be also set to an empty or blank value). # For details about the reasons behind the get_var_from_file implementation see From 1e9b17c67fec240ee6da2038b72cc485293822a3 Mon Sep 17 00:00:00 2001 From: Johannes Meixner Date: Thu, 11 Apr 2024 13:51:07 +0200 Subject: [PATCH 06/10] Update global-functions.sh Typo fix in comment "interits" -> "inherits" --- usr/share/rear/lib/global-functions.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/share/rear/lib/global-functions.sh b/usr/share/rear/lib/global-functions.sh index 30df54df14..206afb1de8 100644 --- a/usr/share/rear/lib/global-functions.sh +++ b/usr/share/rear/lib/global-functions.sh @@ -36,7 +36,7 @@ function get_var_from_file() { # The first argument $1 is the file name. # The second argument $2 is the name of the variable. # We source the file in a separated shell to avoid failures when the variable is readonly in the current shell - # so the variable cannot be set in the current shell or in a subshell (a subshell interits 'readonly') + # so the variable cannot be set in the current shell or in a subshell (a subshell inherits 'readonly') # (see https://github.com/rear/rear/pull/3171#discussion_r1521750947) # and to avoid failures when any other variable that is set in the file is readonly in the current shell # because sourcing a file where a readonly variable is set causes a panic abort of 'source' at that place From 12c3ccb8f00affa7d3a36e915602abee12328fc5 Mon Sep 17 00:00:00 2001 From: Johannes Meixner Date: Fri, 12 Apr 2024 08:43:41 +0200 Subject: [PATCH 07/10] Update global-functions.sh Renamed get_var_from_file into get_shell_file_config_variable to tell what that function actually is about, see https://github.com/rear/rear/pull/3203#issuecomment-2051071868 --- usr/share/rear/lib/global-functions.sh | 29 +++++++++++++------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/usr/share/rear/lib/global-functions.sh b/usr/share/rear/lib/global-functions.sh index 206afb1de8..3a05d31e47 100644 --- a/usr/share/rear/lib/global-functions.sh +++ b/usr/share/rear/lib/global-functions.sh @@ -14,51 +14,52 @@ function read_and_strip_file () { sed -e '/^[[:space:]]/d;/^$/d;/^#/d' "$filename" } -# Get the value of a non-array variable that is set in a file. -# The get_var_from_file function is meant to be used with files +# Get the value of a non-array variable that is set in a shell-syntax file. +# The get_shell_file_config_variable function is meant to be used with files # like /etc/os-release or certain files in /etc/sysconfig or /etc/default -# that basically only do shell-compatible variable assignments (VAR="value") -# but get_var_from_file is not meant to be used with arbitrary shell scripts +# that basically only do shell-compatible variable assignments (VAR="value"). +# get_shell_file_config_variable must not be used with arbitrary shell scripts # because commands in the file are executed via 'source' so any effects of # executing those commands will happen like changing things in the system. # Zero return code means the variable was set in the file and then # stdout is the value of the variable (could be empty or blank). # Non-zero return code in all other cases. # Usage example: -# if my_var="$( get_var_from_file FILE_NAME VAR_NAME )" ; then +# if my_var="$( get_shell_file_config_variable FILE_NAME VAR_NAME )" ; then # # Code when VAR_NAME was set in FILE_NAME # ... # else # # Code when the value of VAR_NAME is unknown # ... # fi -function get_var_from_file() { +function get_shell_file_config_variable() { # The first argument $1 is the file name. # The second argument $2 is the name of the variable. # We source the file in a separated shell to avoid failures when the variable is readonly in the current shell - # so the variable cannot be set in the current shell or in a subshell (a subshell inherits 'readonly') + # so the variable cannot be set in the current shell or in a subshell which inherits variable settings # (see https://github.com/rear/rear/pull/3171#discussion_r1521750947) # and to avoid failures when any other variable that is set in the file is readonly in the current shell - # because sourcing a file where a readonly variable is set causes a panic abort of 'source' at that place - # when sourcing in a subshell i.e. when get_var_from_file is called as in the above usage example + # because sourcing a file where a readonly variable is set causes immediate exit of a subshell at that place + # when sourcing in a subshell i.e. when get_shell_file_config_variable is called as in the above usage example # (see https://github.com/rear/rear/pull/3165#discussion_r1505473662 # and https://github.com/rear/rear/pull/3165#discussion_r1505520542). # Via 'bash -c' $0 in that bash is set to the first argument so $0 in that bash is the file name # and $1 in that bash is set to the second argument so $1 in that bash is the name of the variable. - # The inital "unset $1 || exit 1" ensures that the variable can be set in the file + # The inital "unset $1 || exit 1" ensures that the variable can be set and is set in the file # in particular it exits if the variable is readonly within that 'bash -c' - # e.g. "get_var_from_file some_file UID" results non-zero return code + # e.g. "get_shell_file_config_variable some_file UID" results non-zero return code # (see https://github.com/rear/rear/pull/3171#issuecomment-2022625255). # The "set -u" after the file was sourced lets the subsequent access of the variable "${!1}" # exit with non-zero return code when the variable was not set in the file. - # The 'source' stdout must be discarded because the get_var_from_file stdout must be only the variable value + # The 'source' stdout is discarded because the get_shell_file_config_variable stdout must be only the variable value # (see https://github.com/rear/rear/pull/3171#issuecomment-2018002598). # The 'source' return code is ignored because 'source' returns the status of the last sourced command # (see https://github.com/rear/rear/pull/3171#issuecomment-2019531750) # but we are not interested in the status of the last command in the file but only whether or not # the variable was set in the file (it could be also set to an empty or blank value). - # For details about the reasons behind the get_var_from_file implementation see - # https://github.com/rear/rear/pull/3171 + # For details about the reasons behind the get_shell_file_config_variable implementation + # see https://github.com/rear/rear/pull/3171 (there the function name had been get_var_from_file) + # and https://github.com/rear/rear/pull/3203 bash -c 'unset $1 || exit 1 ; source "$0" >/dev/null ; set -u ; echo "${!1}"' "$1" "$2" } From f79454fe2101b50180ba5abf79e68d581a7cf317 Mon Sep 17 00:00:00 2001 From: Johannes Meixner Date: Mon, 15 Apr 2024 08:56:10 +0200 Subject: [PATCH 08/10] Update global-functions.sh Renamed get_shell_file_config_variable into source_variable_from_file to make it explicit that the file is sourced. --- usr/share/rear/lib/global-functions.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/usr/share/rear/lib/global-functions.sh b/usr/share/rear/lib/global-functions.sh index 1402ffe21f..14b0d1da1e 100644 --- a/usr/share/rear/lib/global-functions.sh +++ b/usr/share/rear/lib/global-functions.sh @@ -15,24 +15,24 @@ function read_and_strip_file () { } # Get the value of a non-array variable that is set in a shell-syntax file. -# The get_shell_file_config_variable function is meant to be used with files +# The source_variable_from_file function is meant to be used with files # like /etc/os-release or certain files in /etc/sysconfig or /etc/default # that basically only do shell-compatible variable assignments (VAR="value"). -# get_shell_file_config_variable must not be used with arbitrary shell scripts +# source_variable_from_file must not be used with arbitrary shell scripts # because commands in the file are executed via 'source' so any effects of # executing those commands will happen like changing things in the system. # Zero return code means the variable was set in the file and then # stdout is the value of the variable (could be empty or blank). # Non-zero return code in all other cases. # Usage example: -# if my_var="$( get_shell_file_config_variable FILE_NAME VAR_NAME )" ; then +# if my_var="$( source_variable_from_file FILE_NAME VAR_NAME )" ; then # # Code when VAR_NAME was set in FILE_NAME # ... # else # # Code when the value of VAR_NAME is unknown # ... # fi -function get_shell_file_config_variable() { +function source_variable_from_file() { # The first argument $1 is the file name. # The second argument $2 is the name of the variable. # We source the file in a separated shell to avoid failures when the variable is readonly in the current shell @@ -40,24 +40,24 @@ function get_shell_file_config_variable() { # (see https://github.com/rear/rear/pull/3171#discussion_r1521750947) # and to avoid failures when any other variable that is set in the file is readonly in the current shell # because sourcing a file where a readonly variable is set causes immediate exit of a subshell at that place - # when sourcing in a subshell i.e. when get_shell_file_config_variable is called as in the above usage example + # when sourcing in a subshell i.e. when source_variable_from_file is called as in the usage example above # (see https://github.com/rear/rear/pull/3165#discussion_r1505473662 - # and https://github.com/rear/rear/pull/3165#discussion_r1505520542). + # and https://github.com/rear/rear/pull/3165#discussion_r1505520542). # Via 'bash -c' $0 in that bash is set to the first argument so $0 in that bash is the file name # and $1 in that bash is set to the second argument so $1 in that bash is the name of the variable. # The inital "unset $1 || exit 1" ensures that the variable can be set and is set in the file # in particular it exits if the variable is readonly within that 'bash -c' - # e.g. "get_shell_file_config_variable some_file UID" results non-zero return code + # e.g. "source_variable_from_file some_file UID" results non-zero return code # (see https://github.com/rear/rear/pull/3171#issuecomment-2022625255). # The "set -u" after the file was sourced lets the subsequent access of the variable "${!1}" # exit with non-zero return code when the variable was not set in the file. - # The 'source' stdout is discarded because the get_shell_file_config_variable stdout must be only the variable value + # The 'source' stdout is discarded because the source_variable_from_file stdout must be only the variable value # (see https://github.com/rear/rear/pull/3171#issuecomment-2018002598). # The 'source' return code is ignored because 'source' returns the status of the last sourced command # (see https://github.com/rear/rear/pull/3171#issuecomment-2019531750) # but we are not interested in the status of the last command in the file but only whether or not # the variable was set in the file (it could be also set to an empty or blank value). - # For details about the reasons behind the get_shell_file_config_variable implementation + # For details about the reasons behind the source_variable_from_file implementation # see https://github.com/rear/rear/pull/3171 (there the function name had been get_var_from_file) # and https://github.com/rear/rear/pull/3203 bash -c 'unset $1 || exit 1 ; source "$0" >/dev/null ; set -u ; echo "${!1}"' "$1" "$2" From 5cafe6d8ce5d0125b49da021e8a35c492f58c125 Mon Sep 17 00:00:00 2001 From: Johannes Meixner Date: Mon, 15 Apr 2024 15:32:15 +0200 Subject: [PATCH 09/10] Update global-functions.sh Added new helper function is_trustworthy_for_root to check if only 'root' could have written a file which makes such files trustworthy to be used by ReaR and call that helper function in source_variable_from_file(), see https://github.com/rear/rear/pull/3203#issuecomment-2056760487 --- usr/share/rear/lib/global-functions.sh | 33 +++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/usr/share/rear/lib/global-functions.sh b/usr/share/rear/lib/global-functions.sh index 14b0d1da1e..0d541d8e86 100644 --- a/usr/share/rear/lib/global-functions.sh +++ b/usr/share/rear/lib/global-functions.sh @@ -5,6 +5,35 @@ # This file is part of Relax-and-Recover, licensed under the GNU General # Public License. Refer to the included COPYING for full text of license. +# A generic method how to avoid problems +# with safely using untrustworthy files, for example +# safely processing/interpreting untrustworthy files +# or safely using data from untrustworthy files, +# is to not use untrustworthy files. +# The idea behind is that a file is untrustworthy +# for a particular user account, +# if other users could have modified that file. +# In other words: +# Only those files are trustworthy for a particular user account, +# where only that particular user could have written the file. +# For ReaR this means: +# Only those files are trustworthy to be used by ReaR +# where only 'root' could have written the file. +# To check if only 'root' could have written a file +# the only possible way in practice is +# to check the current file owner, group, and permissions: +function is_trustworthy_for_root () { + local filename="$1" + local resolved_file + resolved_file="$( readlink -e "$filename" )" || return 1 + # Owner name and group name must be 'root root': + test "$( stat -c '%U %G' $resolved_file )" = "root root" || return 1 + # Neither group nor others must have write permissions + # so the human readable permission string must be '-' + # for group and others for example like "-rwxr-xr-x" + [[ "$( stat -c '%A' $resolved_file )" == ?????-??-? ]] +} + # Extract the real content from a config file provided as argument. # It outputs non-empty and non-comment lines that do not start with a space. # In other words it strips comments, empty lines, and lines with leading space(s): @@ -35,6 +64,8 @@ function read_and_strip_file () { function source_variable_from_file() { # The first argument $1 is the file name. # The second argument $2 is the name of the variable. + # Do not source files that could have been modified by non-root users: + is_trustworthy_for_root "$1" || return 1 # We source the file in a separated shell to avoid failures when the variable is readonly in the current shell # so the variable cannot be set in the current shell or in a subshell which inherits variable settings # (see https://github.com/rear/rear/pull/3171#discussion_r1521750947) @@ -59,7 +90,7 @@ function source_variable_from_file() { # the variable was set in the file (it could be also set to an empty or blank value). # For details about the reasons behind the source_variable_from_file implementation # see https://github.com/rear/rear/pull/3171 (there the function name had been get_var_from_file) - # and https://github.com/rear/rear/pull/3203 + # and https://github.com/rear/rear/pull/3203 bash -c 'unset $1 || exit 1 ; source "$0" >/dev/null ; set -u ; echo "${!1}"' "$1" "$2" } From 5430f6282f98a4936c94054b990fdad917df3346 Mon Sep 17 00:00:00 2001 From: Johannes Meixner Date: Mon, 15 Apr 2024 16:29:00 +0200 Subject: [PATCH 10/10] Update global-functions.sh Fixed is_trustworthy_for_root: Only check that the owner name is 'root' because the group does not matter when it has no write permissions. Treat files with an ACL as untrustworthy to be on the safe side because (at last currently) ACLs are not checked. See https://github.com/rear/rear/pull/3203#issuecomment-2056911103 --- usr/share/rear/lib/global-functions.sh | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/usr/share/rear/lib/global-functions.sh b/usr/share/rear/lib/global-functions.sh index 0d541d8e86..3b92211945 100644 --- a/usr/share/rear/lib/global-functions.sh +++ b/usr/share/rear/lib/global-functions.sh @@ -6,7 +6,7 @@ # Public License. Refer to the included COPYING for full text of license. # A generic method how to avoid problems -# with safely using untrustworthy files, for example +# how to safely use untrustworthy files, for example # safely processing/interpreting untrustworthy files # or safely using data from untrustworthy files, # is to not use untrustworthy files. @@ -18,20 +18,23 @@ # where only that particular user could have written the file. # For ReaR this means: # Only those files are trustworthy to be used by ReaR -# where only 'root' could have written the file. +# when only 'root' could have written the file. # To check if only 'root' could have written a file -# the only possible way in practice is +# the only possible way in practice (there is no history) is # to check the current file owner, group, and permissions: function is_trustworthy_for_root () { local filename="$1" local resolved_file resolved_file="$( readlink -e "$filename" )" || return 1 - # Owner name and group name must be 'root root': - test "$( stat -c '%U %G' $resolved_file )" = "root root" || return 1 + # ACLs are not checked so treat files with ACL as untrustworthy to be on the safe side. + # It seems only 'ls -l' shows when there is an ACL (by '+' appended to the permissions): + test "$( ls -ld1 "$resolved_file" | cut -b11 )" = "+" && return 1 + # Owner name must be 'root': + test "$( stat -c '%U' "$resolved_file" )" = "root" || return 1 # Neither group nor others must have write permissions - # so the human readable permission string must be '-' - # for group and others for example like "-rwxr-xr-x" - [[ "$( stat -c '%A' $resolved_file )" == ?????-??-? ]] + # so the human readable permissions string must be '-' + # for group and others, for example as in "-rwxr-xr-x" + [[ "$( stat -c '%A' "$resolved_file" )" == ?????-??-? ]] } # Extract the real content from a config file provided as argument.