/* * Medal of Honor: Allied Assault Linux dedicated server run helper * Part of dedtools * Adds these features to mohaa_lnxded: * chroot (especially useful with chroot restrictions in kernel) * setuid/setgid * going to background and setting up logfile * pidfile (pidfile deleting is currently commented out) * enabling core dumps * 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 #include static void (*old_f)(FILE *stream, char *buf) = 0; static sighandler_t (*old_signal)(int signum, sighandler_t handler) = 0; static const char *pidfile = 0; /* -- We do not want it now static void (*old__exit)(int status) = 0; // hook _exit for deleting pidfile void _exit(int status) { if (!old__exit) { old__exit = dlsym(RTLD_NEXT,"_exit"); if (!old__exit) exit(-1); } if (pidfile) unlink(pidfile); _exit(status); } */ // create pidfile static void setup_pidfile() { pidfile = getenv("MOHAA_PIDFILE"); if (!pidfile) return; FILE *f = fopen(pidfile,"w"); if (f) { fprintf(f,"%i",(int)getpid()); fprintf(stderr, "Writing pidfile\n"); fclose(f); } } // 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"); } 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("MOHAA_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("MOHAA_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"); } } sighandler_t signal(int signum, sighandler_t handler) { if (!old_signal) { old_signal = dlsym(RTLD_NEXT,"signal"); if (!old_signal) exit(-1); } if (signum == SIGSEGV) return old_signal(signum, SIG_DFL); if (signum == SIGABRT) return old_signal(signum, SIG_DFL); return old_signal(signum, handler); } void setup_coredump() { setrlimit(RLIMIT_CORE, &((const struct rlimit){RLIM_INFINITY, RLIM_INFINITY})); prctl(PR_SET_DUMPABLE, 1); } // the first function called by mohaa_lnxded void setbuf(FILE *stream, char *buf) { if (!old_f) { old_f = dlsym(RTLD_NEXT,"setbuf"); if (!old_f) exit(-1); } static int done = 0; if (!done) { fprintf(stderr, "mohaa_chroot hooked!\n"); droppriv_prep(); chroot_it(); droppriv(); background(); setup_pidfile(); setup_coredump(); done = 1; } return old_f(stream, buf); }