From 2ef31bb41f1f04a9d7341e7b2fe683f71e922097 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 5 Nov 2007 22:49:53 -0500 Subject: store empty directories and restore in etckeeper init While working on this, I had to consider security policies -- is it ok if etckeeper init can run code from the /etc repository? I've decided this should be ok, and documented that it should only be run on trusted repos. Note that metastore could also be exploited by untrusted repos, and of course, note that you're checking out your *** /etc *** so it damn well better be trusted! With that determined, I decided to use a simple shell script to hold the empty directory info and allow them to be easily created. Expanding this for other files git can't represent is a possibility.. --- README | 33 +++++++++++++++++---------------- init.d/05restore-etckeeper | 8 ++++++++ init.d/10restore-metadata | 5 +++++ pre-commit.d/10store-empty-directory | 19 +++++++++++++++++++ pre-commit.d/10store-metadata | 18 ------------------ pre-commit.d/10warn-empty-directory | 6 ------ pre-commit.d/20store-metadata | 18 ++++++++++++++++++ 7 files changed, 67 insertions(+), 40 deletions(-) create mode 100755 init.d/05restore-etckeeper create mode 100755 pre-commit.d/10store-empty-directory delete mode 100755 pre-commit.d/10store-metadata delete mode 100755 pre-commit.d/10warn-empty-directory create mode 100755 pre-commit.d/20store-metadata diff --git a/README b/README index 2cf8410..4900eeb 100644 --- a/README +++ b/README @@ -6,7 +6,7 @@ permissions of `/etc/shadow`. It's quite modular and configurable, while also being simple to use if you understand the basics of working with git. -## security warning +## security warnings First, a big warning: By checking /etc into revision control, you are creating a copy of files like /etc/shadow that must remain secret. Anytime @@ -23,6 +23,9 @@ it out world readable, before etckeeper fixes the permissions. The tutorial has some examples of safe ways to avoid these problems when cloning an /etc repository. +Also note that `etckeeper init` runs code stored in the git repository. +So don't use it on git repositories from untrusted sources. + ## what etckeeper does @@ -40,21 +43,19 @@ empty directories, and special files. git has only limited tracking of file metadata, being able to track the executable bit, but not other permissions or owner info. So file metadata storage is handled by `metastore`. Amoung other chores, `etckeeper init` -sets up a git hook that use `metastore` to store metadata about file -owners, permissions, and even extended attributes into a /etc/.metadata -file. This metadata is stored in git along with everything else, and can be -applied if the repo should need to be checked back out. +sets up a `pre-commit` hook that uses `metastore` to store metadata about +file owners, permissions, and even extended attributes into a +`/etc/.metadata` file. This metadata is stored in git along with everything +else, and can be applied if the repo should need to be checked back out. -git cannot track empty directories. So `etckeeper init` also sets up a git -hook to run `etckeeper pre-commit`, which checks for empty directories -before committing, and warns about them. You can then either ignore the -empty directory, if it's not significant, or put a file (such as -`.gitignore`) in the directory to enable git to track it. +git cannot track empty directories, but they can be significant sometimes +in /etc. So the `pre-commit` hook also stores information that can be used +to recreate the empty directories in a `/etc/.etckeeper` file. git doesn't support several special files that you _probably_ won't have in /etc, such as unix sockets, named pipes, hardlinked files (but softlinks -are fine), and device files. Again git hooks are used to warn if your /etc -contains such untrackable special files. +are fine), and device files. The `pre-commit` hook will warn if your /etc +contains such special files. ## tutorial @@ -127,14 +128,14 @@ Each etckeeper command uses `run-parts` to run the executable files in `/etc/etckeeper/$command.d/`. By default these directories contain a bunch of symlinks to the actual files; you can remove or reorder the symlinks, or add your own custom files. Each individual file is short, simple, and does -only one action. You can even just symlink in existing programs to run -them. +only one action. -For example, here's how to configure it to run `git-gc` after each apt run, +For example, here's how to configure it to run `git gc` after each apt run, which will save a lot of disk space: cd /etc/etckeeper/post-apt.d - ln -s /usr/bin/git-gc 99git-gc + (echo '#!/bin/sh' ; echo 'exec git-gc') > 99git-gc + chmod +x 99git-gc git add . git-commit -m "run git-gc after each apt run" diff --git a/init.d/05restore-etckeeper b/init.d/05restore-etckeeper new file mode 100755 index 0000000..376524c --- /dev/null +++ b/init.d/05restore-etckeeper @@ -0,0 +1,8 @@ +#!/bin/sh +set -e + +# Yes, this runs code from the repository. As documented, etckeeper-init +# should only be run on repositories you trust. +if [ -e .etckeeper ]; then + . ./.etckeeper +fi diff --git a/init.d/10restore-metadata b/init.d/10restore-metadata index fdb1f8e..cd6174c 100755 --- a/init.d/10restore-metadata +++ b/init.d/10restore-metadata @@ -1,5 +1,10 @@ #!/bin/sh set -e + +# Note that metastore doesn't check that the .metastore file only changes +# perms of files in the current directory. It's ok to trust the .metastore +# file won't do anything shady, because, as documented, etckeeper-init +# should only be run on repositories you trust. if [ -e .metadata ]; then metastore --apply fi diff --git a/pre-commit.d/10store-empty-directory b/pre-commit.d/10store-empty-directory new file mode 100755 index 0000000..bc698e2 --- /dev/null +++ b/pre-commit.d/10store-empty-directory @@ -0,0 +1,19 @@ +#!/bin/sh +set -ex + +# Make sure the file is not readable by others, since it can leak +# information about contents of non-readable directories in /etc. +umask 077 + +if [ -e .etckeeper ]; then + egrep -v '^mkdir ' .etckeeper > .etckeeper.new || true +fi +find -type d -empty | grep -v /.git/ | sort | + sed -e "s/^/mkdir -p '/" -e "s/\$/'/" >> .etckeeper.new + +if [ ! -e .etckeeper ] || ! cmp -s .etckeeper .etckeeper.new ; then + mv -f .etckeeper.new .etckeeper + git add .etckeeper +else + rm -f .etckeeper.new +fi diff --git a/pre-commit.d/10store-metadata b/pre-commit.d/10store-metadata deleted file mode 100755 index b878abd..0000000 --- a/pre-commit.d/10store-metadata +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh -set -e - -# Make sure the file is not readable by others, since it can leak -# information about contents of non-readable directories in /etc. -umask 077 - -# ensure the file exists so that it will list its own metadata -if [ ! -e .metadata ]; then - metastore --save -fi - -# metastore doesn't produce the same output file for the same metadata -# everytime, so avoid changing the file if nothing really changed. -if [ ! -z "$(metastore --compare)" ]; then - metastore --save - git add .metadata -fi diff --git a/pre-commit.d/10warn-empty-directory b/pre-commit.d/10warn-empty-directory deleted file mode 100755 index b850c86..0000000 --- a/pre-commit.d/10warn-empty-directory +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -set -e -empty=$(find -type d -empty | grep -v /.git/) || true -if [ -n "$empty" ]; then - echo "etckeeper warning: there are some empty directories, which git will ignore" >&2 -fi diff --git a/pre-commit.d/20store-metadata b/pre-commit.d/20store-metadata new file mode 100755 index 0000000..b878abd --- /dev/null +++ b/pre-commit.d/20store-metadata @@ -0,0 +1,18 @@ +#!/bin/sh +set -e + +# Make sure the file is not readable by others, since it can leak +# information about contents of non-readable directories in /etc. +umask 077 + +# ensure the file exists so that it will list its own metadata +if [ ! -e .metadata ]; then + metastore --save +fi + +# metastore doesn't produce the same output file for the same metadata +# everytime, so avoid changing the file if nothing really changed. +if [ ! -z "$(metastore --compare)" ]; then + metastore --save + git add .metadata +fi -- cgit v1.2.3