This adds a 'parse_envfile' function that reads files such as
/etc/locale.conf and /etc/vconsole.conf without sourcing them as bash
logic. Several benefits are realized from this:

- Impossible to execute arbitrary code
- Bad syntax won't prevent the entire file from being read
- Possible to limit what variables are allowed

Signed-off-by: Dave Reisner <[email protected]>
---
 functions  |   50 ++++++++++++++++++++++++++++++++++++++++++++++++--
 rc.sysinit |    4 ++--
 2 files changed, 50 insertions(+), 4 deletions(-)

diff --git a/functions b/functions
index ce664ed..387f2af 100644
--- a/functions
+++ b/functions
@@ -9,6 +9,8 @@ localevars=(LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE 
LC_MONETARY
             LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE
             LC_MEASUREMENT LC_IDENTIFICATION LC_ALL)
 
+vconsolevars=(KEYMAP KEYMAP_TOGGLE FONT FONT_MAP FONT_UNIMAP)
+
 if [[ $1 == "start" ]]; then
        if [[ $STARTING ]]; then
                echo "A daemon is starting another daemon, this is unlikely to 
work as intended."
@@ -70,12 +72,56 @@ unset TZ
 # sanitize the locale settins
 unset "${localevars[@]}"
 
+parse_envfile() {
+       local file=$1 validkeys=${@:2} ret=0 lineno=0 key= val=
+
+       if [[ -z $file ]]; then
+               printf "error: no environment file specified\n"
+               return 1
+       fi
+
+       if [[ ! -f $file ]]; then
+               printf "error: cannot parse \`%s': No such file or directory\n" 
"$file"
+               return 1
+       fi
+
+       if [[ ! -r $file ]]; then
+               printf "error: cannot read \`%s': Permission denied\n" "$file"
+               return 1
+       fi
+
+       while IFS='=' read -r key val; do
+               (( ++lineno ))
+
+               # trim whitespace, avoiding usage of a tempfile
+               key=$(echo "$1" | { read -r val; echo "$val"; })
+               val=$(echo "$1" | { read -r val; echo "$val"; })
+
+               [[ $key ]] || continue
+
+               if [[ -z $val ]]; then
+                       printf "error: found key \`%s' without value on line %s 
of %s\n" \
+                                       "$key" "$lineno" "$file"
+                       (( ++ret ))
+                       continue
+               fi
+
+               # ignore invalid keys if we have a list of valid ones
+               if (( ${#validkeys[*]} )); then
+                       in_array "$key" "${validkeys[@]}" || continue
+               fi
+
+               export "$key=$val" || (( ++ret ))
+       done <"$file"
+
+       return $ret
+}
+
 if [[ $DAEMON_LOCALE = [yY][eE][sS] ]]; then
        LANG=${LOCALE:-C}
        if [[ -r /etc/locale.conf ]]; then
-               . /etc/locale.conf
+               parse_envfile /etc/locale.conf "${localevars[@]}"
        fi
-       export "${localevars[@]}"
 else
        export LANG=C
 fi
diff --git a/rc.sysinit b/rc.sysinit
index eb66935..654a409 100755
--- a/rc.sysinit
+++ b/rc.sysinit
@@ -237,7 +237,7 @@ if [[ $HOSTNAME ]]; then
 fi
 
 if [[ -s /etc/locale.conf ]]; then
-       . /etc/locale.conf
+       parse_envfile /etc/locale.conf "LANG"
        [[ $LANG ]] && LOCALE=$LANG
 fi
 if [[ ${LOCALE,,} =~ utf ]]; then
@@ -263,7 +263,7 @@ else
 fi
 
 if [[ -s /etc/vconsole.conf ]]; then
-       . /etc/vconsole.conf
+       parse_envfile /etc/vconsole.conf "${vconsolevars[@]}"
        [[ $FONT ]] && CONSOLEFONT=$FONT
        [[ $FONT_MAP ]] && CONSOLEMAP=$FONT_MAP
 fi
-- 
1.7.7.2

Reply via email to