/* * Half-Life Linux dedicated server run helper * Part of dedtools * Adds these features to hlds: * chroot (especially useful with chroot restrictions in kernel) * setuid/setgid * going to background and setting up logfile * Code by Tomas Janousek * This is GPL code. * * Refer to README.chroot about setting up chroot environment */ #include #include #include #include #include #include #include #include #include #include #include #include static char *(*old_f)(char *buf, size_t size) = 0; // chroot and chdir to / static void chroot_it() { if (chroot(".")) { fprintf(stderr, "Could not chroot (%s)\n", strerror(errno)); exit(-1); } if (chdir("/")) { fprintf(stderr, "Could not chdir (%s)\n", strerror(errno)); exit(-1); } fprintf(stderr, "Chrooted successfully\n"); } // let libc load nss before chroot static void init_resolv() { gethostbyname(""); } static struct passwd *userent = 0; // prepare uid and gid for dropping privileges // (we can't read passwd after chroot) static void droppriv_prep() { const char *user = getenv("HLDS_USER"); if (user) { userent = getpwnam(user); if (!userent) { fprintf(stderr, "Specified user does not exist (%s)\n", strerror(errno)); exit(-1); } } } // drop privileges static void droppriv() { if (userent) { if (setgid(userent->pw_gid)) { fprintf(stderr, "Could not setgid (%s)\n", strerror(errno)); exit(-1); } if (setuid(userent->pw_uid)) { fprintf(stderr, "Could not setuid (%s)\n", strerror(errno)); exit(-1); } fprintf(stderr, "Privileges dropped successfully\n"); } else fprintf(stderr, "Will not setuid!\n"); } // fork into background and setup logfile static void background() { if (daemon(1, 0)) { fprintf(stderr, "Could not daemon (%s)\n", strerror(errno)); exit(-1); } const char *log = getenv("HLDS_LOG"); if (log) { int fd = open(log, O_WRONLY | O_APPEND | O_CREAT, 0666); if (fd < 0) { fprintf(stderr, "Could not open log (%s)\n", strerror(errno)); exit(-1); } dup2(fd, 1); dup2(fd, 2); close(fd); fprintf(stderr, "Logfile opened\n"); } } // one of the first functions called by hlds char *getcwd(char *buf, size_t size) { if (!old_f) { old_f = dlsym(RTLD_NEXT,"getcwd"); if (!old_f) exit(-1); } static int done = 0; if (!done) { fprintf(stderr, "hlds_chroot hooked!\n"); droppriv_prep(); init_resolv(); chroot_it(); droppriv(); background(); done = 1; } return old_f(buf, size); }