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 <dreisner@archlinux.org> --- 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