+/*
+ * Chroot into a directory after checking it for safety: all path components
+ * must be root-owned directories with strict permissions.
+ */
+static void
+safely_chroot(const char *path, uid_t uid)
+{
+ const char *cp;
+ char component[MAXPATHLEN];
+ struct stat st;
+
+ if (*path != '/')
+ fatal("chroot path does not begin at root");
+ if (strlen(path) >= sizeof(component))
+ fatal("chroot path too long");
+
+ /*
+ * Descend the path, checking that each component is a
+ * root-owned directory with strict permissions.
+ */
+ for (cp = path; cp != NULL;) {
+ if ((cp = strchr(cp, '/')) == NULL)
+ strlcpy(component, path, sizeof(component));
+ else {
+ cp++;
+ memcpy(component, path, cp - path);
+ component[cp - path] = '\0';
+ }
+
+ debug3("%s: checking '%s'", __func__, component);
+
+ if (stat(component, &st) != 0)
+ fatal("%s: stat(\"%s\"): %s", __func__,
+ component, strerror(errno));
+ if (st.st_uid != 0 || (st.st_mode & 022) != 0)
+ fatal("bad ownership or modes for chroot "
+ "directory %s\"%s\"",
+ cp == NULL ? "" : "component ", component);
+ if (!S_ISDIR(st.st_mode))
+ fatal("chroot path %s\"%s\" is not a directory",
+ cp == NULL ? "" : "component ", component);
+
+ }
+
+ if (chdir(path) == -1)
+ fatal("Unable to chdir to chroot path \"%s\": "
+ "%s", path, strerror(errno));
+ if (chroot(path) == -1)
+ fatal("chroot(\"%s\"): %s", path, strerror(errno));
+ if (chdir("/") == -1)
+ fatal("%s: chdir(/) after chroot: %s",
+ __func__, strerror(errno));
+ verbose("Changed root directory to \"%s\"", path);
+}
+