From f2fb351c391dca7c188a8623e71519619c2ce9a0 Mon Sep 17 00:00:00 2001 From: Mat M Date: Sun, 8 Dec 2019 00:25:53 +0100 Subject: Do not symlink a symlink in mkrc We have a bug when calling mkrc(1) on a symlink: ```sh mkrc ~/.vimrc # links ~/.vimrc to ~/.dotfiles/vimrc mkrc ~/.vimrc # deletes ~/.dotfiles/vimrc ``` This catches that case ahead of time, preventing the user from running mkrc(1) on a symlink. Fix #144. --- Makefile.am | 1 + NEWS.md.in | 2 ++ bin/mkrc.in | 23 +++++++++++++++++++++++ bin/rcup.in | 4 ---- share/rcm.sh.in | 4 ++++ test/mkrc-no-symlinks.t | 26 ++++++++++++++++++++++++++ 6 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 test/mkrc-no-symlinks.t diff --git a/Makefile.am b/Makefile.am index 16164d9..4af524d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -24,6 +24,7 @@ TESTS = \ test/mkrc-copy-file.t \ test/mkrc-host-file.t \ test/mkrc-hostname.t \ + test/mkrc-no-symlinks.t \ test/mkrc-simple-output.t \ test/mkrc-spaces.t \ test/mkrc-symlink-dirs.t \ diff --git a/NEWS.md.in b/NEWS.md.in index 6af5d4e..4461a2f 100644 --- a/NEWS.md.in +++ b/NEWS.md.in @@ -1,5 +1,7 @@ rcm (@PACKAGE_VERSION@) unstable; urgency=low + * Fix #144 and more: all symlinks in input are rejected (Mat M) + -- Mike Burns Fri, 13 Jul 2018 14:12:00 -0500 rcm (1.3.3) unstable; urgency=low diff --git a/bin/mkrc.in b/bin/mkrc.in index 5d6af7e..d246c33 100755 --- a/bin/mkrc.in +++ b/bin/mkrc.in @@ -20,6 +20,28 @@ destination() { fi } +exit_if_dangerous() { + local file="$1" + + if [ -L "$file" ]; then + $ERROR 1 "'$file' is a symlink. Cannot process file." + elif is_nested "$file"; then + # Remove DEST_DIR in case $HOME is under a symlink + saved_ifs="$IFS" + IFS=/ + set -- $(dirname "$file" | sed "s|$DEST_DIR/||") + IFS="$saved_ifs" + + built_dir="$DEST_DIR" + for dir in $@; do + built_dir="$built_dir/$dir" + if [ -L "$built_dir" ]; then + $ERROR 1 "'$file' path contains a symlink ($dir). Cannot process file." + fi + done + fi +} + show_help() { local exit_code=${1:-0} @@ -84,6 +106,7 @@ fi files="" for i; do + exit_if_dangerous "$i" files="$(printf "$files\n$i")" done diff --git a/bin/rcup.in b/bin/rcup.in index 910e534..78f5faa 100755 --- a/bin/rcup.in +++ b/bin/rcup.in @@ -121,10 +121,6 @@ replace_file() { link_file "$src" "$dest" "$sigil" } -is_nested() { - echo "$1" | sed "s:$DEST_DIR/::" | grep '/' >/dev/null -} - is_identical() { diff -c "$1" "$2" > /dev/null 2>&1 } diff --git a/share/rcm.sh.in b/share/rcm.sh.in index a2b4492..f7c6137 100644 --- a/share/rcm.sh.in +++ b/share/rcm.sh.in @@ -58,6 +58,10 @@ is_relative() { echo "$1" | grep -v '^/' >/dev/null } +is_nested() { + echo "$1" | sed "s|$DEST_DIR/||" | grep '/' >/dev/null +} + version() { cat << EOV $1 (rcm) $VERSION diff --git a/test/mkrc-no-symlinks.t b/test/mkrc-no-symlinks.t new file mode 100644 index 0000000..e37d56a --- /dev/null +++ b/test/mkrc-no-symlinks.t @@ -0,0 +1,26 @@ + $ . "$TESTDIR/helper.sh" + +Passing a linked file is rejected. +We need a second path not under what will be $HOME + + $ EXTDIR="${CRAMTMP}2" + > mkdir -p "$EXTDIR" + > echo 'Content' > "$EXTDIR/example" + > ln -s "$EXTDIR/example" "$HOME/.example" + + $ mkrc .example + '.example' is a symlink. Cannot process file. + [1] + + $ refute "is a symlink" -h $HOME/.dotfiles/.example + +Passing a file in one linked dir is rejected + + $ mkdir "$HOME/.config" + > ln -s "$EXTDIR/" "$HOME/.config/tmpdir" + + $ mkrc -v .config/tmpdir/example + '.config/tmpdir/example' path contains a symlink (tmpdir). Cannot process file. + [1] + + $ refute "is a symlink" -h "$HOME/.dotfiles/config/tmpdir/example" -- cgit v1.2.3