diff --git a/.gitignore b/.gitignore
index 9aa21f85c29207cb979c1a4b94d2d27ac1336cc0..9bc7a3a88f7d9b06132e07173e2a650bc3c628ba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,6 +32,7 @@
 
 # daemons
 /daemons/daemon-util
+/daemons/ensure-dirs
 /daemons/ganeti-cleaner
 
 # devel
diff --git a/Makefile.am b/Makefile.am
index 35b17768f1328771a8a22a556e8aa8ad38cd7875..8dbd86bbd1fae2163d67456f6b25eb0943eb7cf5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -64,6 +64,7 @@ CLEANFILES = \
 	$(addsuffix /*.py[co],$(DIRS)) \
 	autotools/replace_vars.sed \
 	daemons/daemon-util \
+	daemons/ensure-dirs \
 	daemons/ganeti-cleaner \
 	devel/upload \
 	doc/examples/bash_completion \
@@ -257,6 +258,7 @@ pkglib_python_scripts = \
 
 pkglib_SCRIPTS = \
 	daemons/daemon-util \
+	daemons/ensure-dirs \
 	$(pkglib_python_scripts)
 
 EXTRA_DIST = \
@@ -270,6 +272,7 @@ EXTRA_DIST = \
 	autotools/testrunner \
 	$(RUN_IN_TEMPDIR) \
 	daemons/daemon-util.in \
+	daemons/ensure-dirs.in \
 	daemons/ganeti-cleaner.in \
 	$(pkglib_python_scripts) \
 	devel/upload.in \
@@ -541,6 +544,7 @@ $(REPLACE_VARS_SED): Makefile
 	  echo 's#@GNTADMINGROUP@#$(ADMIN_GROUP)#g'; \
 	  echo 's#@GNTCONFDGROUP@#$(CONFD_GROUP)#g'; \
 	  echo 's#@GNTMASTERDGROUP@#$(MASTERD_GROUP)#g'; \
+	  echo 's#@GNTDAEMONSGROUP@#$(DAEMONS_GROUP)#g'; \
 	} > $@
 
 # We need to create symlinks because "make distcheck" will not install Python
diff --git a/daemons/daemon-util.in b/daemons/daemon-util.in
index 4d47bd937bf12565ec41fb456ea477f3c9ab1366..4d6054d405c2eab06006ca48cab5476360a0ec6d 100755
--- a/daemons/daemon-util.in
+++ b/daemons/daemon-util.in
@@ -149,6 +149,8 @@ start() {
   # Read $<daemon>_ARGS and $EXTRA_<daemon>_ARGS
   eval local args="\"\$${ucname}_ARGS \$EXTRA_${ucname}_ARGS\""
 
+  @PKGLIBDIR@/ensure-dirs
+
   start-stop-daemon --start --quiet --oknodo \
     --pidfile $(_daemon_pidfile $name) \
     --startas $(_daemon_executable $name) \
diff --git a/daemons/ensure-dirs.in b/daemons/ensure-dirs.in
new file mode 100644
index 0000000000000000000000000000000000000000..b778ff19806c04acd9f392f8b3cbc926768a0e3a
--- /dev/null
+++ b/daemons/ensure-dirs.in
@@ -0,0 +1,67 @@
+#!/bin/bash
+
+set -e
+
+LIBDIR="@LOCALSTATEDIR@/lib"
+DATADIR="${LIBDIR}/ganeti"
+RUNDIR="@LOCALSTATEDIR@/run"
+GNTRUNDIR="${RUNDIR}/ganeti"
+LOGDIR="@LOCALSTATEDIR@/log"
+GNTLOGDIR="${LOGDIR}/ganeti"
+
+_fileset_owner() {
+  case "$1" in
+    masterd)
+      echo "@GNTMASTERUSER@:@GNTMASTERDGROUP@"
+      ;;
+    confd)
+      echo "@GNTCONFDUSER@:@GNTCONFDGROUP@"
+      ;;
+    rapi)
+      echo "@GNTRAPIUSER@:@GNTRAPIGROUP@"
+      ;;
+    daemons)
+      echo "@GNTMASTERUSER@:@GNTDAEMONSGROUP@"
+      ;;
+    *)
+      echo "root:root"
+      ;;
+  esac
+}
+
+_ensure_dir() {
+  local dir="$1"
+  local perm="$2"
+  local owner="$3"
+
+  [ -d "${dir}" ] || mkdir "${dir}"
+  chmod ${perm} "${dir}"
+  chown ${owner} "${dir}"
+}
+
+_ensure_rundir() {
+  _ensure_dir "${GNTRUNDIR}" 0775 "$(_fileset_owner "daemons")"
+  _ensure_dir "${GNTRUNDIR}/socket" 0750 "$(_fileset_owner "daemons")"
+}
+
+_ensure_logdir() {
+  _ensure_dir "${GNTLOGDIR}" 0770 "$(_fileset_owner "daemons")"
+
+  chown $(_fileset_owner "rapi") "${GNTLOGDIR}/rapi-daemon.log"
+}
+
+_operate_while_hold() {
+  local fn=$1
+  local path=$2
+  shift 2
+
+  (cd "${path}";
+   ${fn} "$@")
+}
+
+main() {
+  _operate_while_hold "_ensure_rundir" "${RUNDIR}"
+  _operate_while_hold "_ensure_logdir" "${LOGDIR}"
+}
+
+main "$@"