#include #include #include #include #include #include #include #include #include #include #include #include #define NIFS "IFS= \t\n" #define NPATH "PATH="_PATH_STDPATH static void disable_core_dumps(void) { struct rlimit r = { 0, 0 }; if (setrlimit(RLIMIT_CORE, &r) != 0) { exit(1); } } static void set_minimal_env(void) { extern char **environ; static char **ne = NULL; ne = malloc(3 * sizeof(char *) + sizeof(NIFS) + sizeof(NPATH)); /* Umgebungsvariablen setzen */ ne[0] = (char *)&(ne[3]); memcpy(ne[0], NIFS, sizeof(NIFS)); ne[1] = ne[0] + sizeof(NIFS); memcpy(ne[1], NPATH, sizeof(NPATH)); ne[2] = NULL; /* Alte Umgebung ersetzen */ environ = ne; } static void close_descriptors(void) { int nd; /* Nur Linux, sonst getdtablesize() */ if ((nd = sysconf(_SC_OPEN_MAX)) < 0) { exit(1); } while (--nd > 2) { close(nd); } } static void open_stdfiles(void) { struct stat buf; FILE *f[3]; char *m[3] = { "rb", "wb", "wb" }; int i; f[0] = stdin; f[1] = stdout; f[2] = stderr; for (i = 0; i < 3; i++) { if (fstat(i, &buf) == 0) { continue; } if (errno != EBADF) { exit(1); } if (freopen(_PATH_DEVNULL, m[i], f[i]) != f[i]) { exit(1); } } } static void reset_sighandlers(void) { int i; for (i = 1; i <= NSIG; i++) { signal(i, SIG_DFL); } } /* Sicherere Version in Folge 2! */ static void change_workdir(char *path) { if (chdir(path) != 0) { exit(1); } } static void safe_chroot(char *path) { /* Erst alle Deskriptoren zumachen */ if (chroot(path) != 0) { exit (1); } if (chdir("/") != 0) { exit(1); } /* Rootrechte abgeben */ } static void set_credentials(uid_t uid, gid_t gid) { /* Nur root darf setgroups aufrufen */ if (geteuid() == 0 && setgroups(1, &gid) != 0) { exit(1); } /* Nur mit Linux: */ if (setregid(gid, gid) != 0) { exit(1); } if (setreuid(uid, uid) != 0) { exit(1); } } int main(void) { /* Die Reihenfolge ist wichtig! */ disable_core_dumps(); reset_sighandlers(); umask(0077); set_minimal_env(); close_descriptors(); open_stdfiles(); safe_chroot("/chroot"); change_workdir("/path/workdir"); set_credentials(geteuid(), getegid()); /* ... */ return 0; }