X-Git-Url: http://git.code-monkey.de/?p=umurmur.git;a=blobdiff_plain;f=src%2Fmain.c;h=d98fb6aca3a89b42fa3d4fbe2d21d51cd74208ec;hp=8c5febd6fb742b291c3d7e1e32ea9ac816ae1dc4;hb=571e132795d595c7c4ce39b5b1bc9aae6a72f4cd;hpb=1c9b1f27ae2c73853f1c493885315506923a04be diff --git a/src/main.c b/src/main.c index 8c5febd..d98fb6a 100644 --- a/src/main.c +++ b/src/main.c @@ -1,5 +1,5 @@ -/* Copyright (C) 2009-2010, Martin Johansson - Copyright (C) 2005-2010, Thorvald Natvig +/* Copyright (C) 2009-2014, Martin Johansson + Copyright (C) 2005-2014, Thorvald Natvig All rights reserved. @@ -29,20 +29,24 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - #include #include #include #include #include #include +#include +#include #include #include #include #include #ifdef _POSIX_PRIORITY_SCHEDULING +#if (_POSIX_PRIORITY_SCHEDULING > 0) +#define POSIX_PRIORITY_SCHEDULING #include #endif +#endif #include "server.h" #include "ssl.h" #include "channel.h" @@ -50,44 +54,136 @@ #include "client.h" #include "conf.h" #include "version.h" +#include "config.h" +#include "sharedmemory.h" +#include "ban.h" char system_string[64], version_string[64]; int bindport; +int bindport6; char *bindaddr; +char *bindaddr6; void lockfile(const char *pidfile) { - int lfp; + int lfp, flags; char str[16]; - - lfp = open(pidfile, O_RDWR|O_CREAT, 0640); - + + /* Don't use O_TRUNC here -- we want to leave the PID file + * unmodified if we cannot lock it. + */ + lfp = open(pidfile, O_WRONLY|O_CREAT, 0640); + if (lfp < 0) Log_fatal("Cannot open PID-file %s for writing", pidfile); - sprintf(str,"%d\n", getpid()); - write(lfp, str, strlen(str)); /* record pid to lockfile */ + + /* Try to lock the file. */ + if (lockf(lfp, F_TLOCK, 0) < 0) { + close(lfp); + + if (errno == EACCES || errno == EAGAIN) + Log_fatal("PID file is locked -- uMurmur already running?"); + + Log_fatal("Cannot lock PID file: %s", strerror(errno)); + } + + /* Now that we locked the file, erase its contents. */ + if (ftruncate(lfp, 0) < 0) { + close(lfp); + Log_fatal("Cannot truncate PID file: %s", strerror(errno)); + } + + snprintf(str,16,"%d\n", getpid()); + (void)write(lfp, str, strlen(str)); /* record pid to lockfile */ Log_info("PID-file: %s", pidfile); + + /* If uMurmur ever starts to fork()+exec(), we don't want it to + * leak the fd to the forked process though. Set the close-on-exec + * flag to prevent leakage. + */ + flags = fcntl(lfp, F_GETFD, 0); + flags |= FD_CLOEXEC; + fcntl(lfp, F_SETFD, (long) flags); + + /* Don't close(lfp) here! + * We want the fd to remain opened so the lock is held until the + * process exits. + */ + lfp = -1; } +/* Drops privileges (if configured to do so). */ +static void switch_user(void) +{ + struct passwd *pwd; + struct group *grp = NULL; + const char *username, *groupname; + gid_t gid; + + username = getStrConf(USERNAME); + groupname = getStrConf(GROUPNAME); + + if (!*username) { + /* It's an error to specify groupname + * but leave username empty. + */ + if (*groupname) + Log_fatal("username missing"); + + /* Nothing to do. */ + return; + } + + pwd = getpwnam(username); + if (!pwd) + Log_fatal("Unknown user '%s'", username); + + if (!*groupname) + gid = pwd->pw_gid; + else { + grp = getgrnam(groupname); + + if (!grp) + Log_fatal("Unknown group '%s'", groupname); + + gid = grp->gr_gid; + } + + if (initgroups(pwd->pw_name, gid)) + Log_fatal("initgroups() failed: %s", strerror(errno)); + + if (setgid(gid)) + Log_fatal("setgid() failed: %s", strerror(errno)); + + if (setuid(pwd->pw_uid)) + Log_fatal("setuid() failed: %s", strerror(errno)); + + if (!grp) + grp = getgrgid(gid); + if (!grp) + Log_fatal("getgrgid() failed: %s", strerror(errno)); + + Log_info("Switch to user '%s' group '%s'", pwd->pw_name, grp->gr_name); +} void signal_handler(int sig) { switch(sig) { - case SIGHUP: - /* XXX - do stuff? */ - Log_info("HUP signal"); - break; - case SIGTERM: - Log_info("TERM signal. Shutting down."); - Server_shutdown(); - break; + case SIGHUP: + Log_info("HUP signal received."); + Log_reset(); + break; + case SIGTERM: + Log_info("TERM signal. Shutting down."); + Server_shutdown(); + break; } } void daemonize() { int i; - + if (getppid() == 1) return; /* already a daemon */ i = fork(); @@ -97,22 +193,26 @@ void daemonize() } if ( i > 0) exit(0); /* parent exits */ - + /* child (daemon) continues */ setsid(); /* obtain a new process group */ for (i = getdtablesize(); i >= 0; --i) close(i); /* close all descriptors */ - + +#ifdef USE_GNUTLS + gnutls_global_init(); +#endif + i = open("/dev/null",O_RDWR); - dup(i); - dup(i); - + (void)dup(i); + (void)dup(i); + umask(027); /* set newly created file permissions */ - chdir("/"); - + (void)chdir("/"); + } -#ifdef _POSIX_PRIORITY_SCHEDULING +#ifdef POSIX_PRIORITY_SCHEDULING void setscheduler() { int rc; @@ -128,16 +228,20 @@ void setscheduler() void printhelp() { - printf("uMurmur version %s. Mumble protocol %d.%d.%d\n", UMURMUR_VERSION, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH); - printf("Usage: umurmurd [-d] [-p ] [-c ] [-h]\n"); - printf(" -d - Do not deamonize\n"); - printf(" -p - Write PID to this file\n"); - printf(" -c - Specify configuration file\n"); -#ifdef _POSIX_PRIORITY_SCHEDULING + printf("uMurmur version %s ('%s'). Mumble protocol %d.%d.%d\n", UMURMUR_VERSION, + UMURMUR_CODENAME, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH); + printf("Usage: umurmurd [-d] [-r] [-h] [-p ] [-t] [-c ] [-a ] [-b ]\n"); + printf(" -d - Do not daemonize - run in foreground.\n"); +#ifdef POSIX_PRIORITY_SCHEDULING printf(" -r - Run with realtime priority\n"); #endif + printf(" -p - Write PID to this file\n"); + printf(" -c - Specify configuration file (default %s)\n", DEFAULT_CONFIG); + printf(" -t - Test config. Error message to stderr + non-zero exit code on error\n"); printf(" -a
- Bind to IP address\n"); + printf(" -A
- Bind to IPv6 address\n"); printf(" -b - Bind to port\n"); + printf(" -B - Bind to port (IPv6)\n"); printf(" -h - Print this help\n"); exit(0); } @@ -145,101 +249,135 @@ void printhelp() int main(int argc, char **argv) { bool_t nodaemon = false; -#ifdef _POSIX_PRIORITY_SCHEDULING +#ifdef POSIX_PRIORITY_SCHEDULING bool_t realtime = false; #endif + bool_t testconfig = false; char *conffile = NULL, *pidfile = NULL; int c; struct utsname utsbuf; - + /* Arguments */ -#ifdef _POSIX_PRIORITY_SCHEDULING - while ((c = getopt(argc, argv, "drp:c:a:b:h")) != EOF) { +#ifdef POSIX_PRIORITY_SCHEDULING + while ((c = getopt(argc, argv, "drp:c:a:A:b:B:ht")) != EOF) { #else - while ((c = getopt(argc, argv, "dp:c:a:b:h")) != EOF) { + while ((c = getopt(argc, argv, "dp:c:a:A:b:B:ht")) != EOF) { #endif - switch(c) { - case 'c': - conffile = optarg; - break; - case 'p': - pidfile = optarg; - break; - case 'a': - bindaddr = optarg; - break; - case 'b': - bindport = atoi(optarg); - break; - case 'd': - nodaemon = true; - break; - case 'h': - printhelp(); - break; -#ifdef _POSIX_PRIORITY_SCHEDULING - case 'r': - realtime = true; - break; + switch(c) { + case 'c': + conffile = optarg; + break; + case 'p': + pidfile = optarg; + break; + case 'a': + bindaddr = optarg; + break; + case 'A': + bindaddr6 = optarg; + break; + case 'b': + bindport = atoi(optarg); + break; + case 'B': + bindport6 = atoi(optarg); + break; + case 'd': + nodaemon = true; + break; + case 'h': + printhelp(); + break; + case 't': + testconfig = true; + break; +#ifdef POSIX_PRIORITY_SCHEDULING + case 'r': + realtime = true; + break; #endif - default: - fprintf(stderr, "Unrecognized option\n"); - printhelp(); - break; + default: + fprintf(stderr, "Unrecognized option\n"); + printhelp(); + break; + } } - } - - if (Conf_init(conffile) != 0) { - fprintf(stderr, "Configuration error\n"); - exit(1); - } - - if (!nodaemon) { - Log_init(false); - daemonize(); - if (pidfile != NULL) - lockfile(pidfile); - } - else - Log_init(true); - - signal(SIGCHLD, SIG_IGN); /* ignore child */ - signal(SIGTSTP, SIG_IGN); /* ignore tty signals */ - signal(SIGTTOU, SIG_IGN); - signal(SIGTTIN, SIG_IGN); - signal(SIGPIPE, SIG_IGN); - signal(SIGHUP, signal_handler); /* catch hangup signal */ - signal(SIGTERM, signal_handler); /* catch kill signal */ - - /* Build system string */ - if (uname(&utsbuf) == 0) { - snprintf(system_string, 64, "%s %s", utsbuf.sysname, utsbuf.machine); - snprintf(version_string, 64, "%s", utsbuf.release); - } - else { - snprintf(system_string, 64, "unknown unknown"); - snprintf(version_string, 64, "unknown"); - } - - /* Initializing */ - SSLi_init(); - Chan_init(); - Client_init(); -#ifdef _POSIX_PRIORITY_SCHEDULING - if (realtime) - setscheduler(); + if (testconfig) { + if (!Conf_ok(conffile)) + exit(1); + else + exit(0); + } + + /* Initialize the config subsystem early; + * switch_user() will need to read some config variables as well as logging. + */ + Conf_init(conffile); + + /* Logging to terminal if not daemonizing, otherwise to syslog or log file. + */ + if (!nodaemon) { + daemonize(); + Log_init(false); + if (pidfile != NULL) + lockfile(pidfile); + } + else Log_init(true); + + signal(SIGCHLD, SIG_IGN); /* ignore child */ + signal(SIGTSTP, SIG_IGN); /* ignore tty signals */ + signal(SIGTTOU, SIG_IGN); + signal(SIGTTIN, SIG_IGN); + signal(SIGPIPE, SIG_IGN); + signal(SIGHUP, signal_handler); /* catch hangup signal */ + signal(SIGTERM, signal_handler); /* catch kill signal */ + + /* Build system string */ + if (uname(&utsbuf) == 0) { + snprintf(system_string, 64, "%s %s", utsbuf.sysname, utsbuf.machine); + snprintf(version_string, 64, "%s", utsbuf.release); + } + else { + snprintf(system_string, 64, "unknown unknown"); + snprintf(version_string, 64, "unknown"); + } + + /* Initializing */ + SSLi_init(); + Chan_init(); + Client_init(); + Ban_init(); + +#ifdef USE_SHAREDMEMORY_API + Sharedmemory_init( bindport, bindport6 ); #endif - - Server_run(); - - SSLi_deinit(); - Chan_free(); - Log_free(); - Conf_deinit(); - - if (pidfile != NULL) - unlink(pidfile); - - return 0; -} + +#ifdef POSIX_PRIORITY_SCHEDULING + if (realtime) + setscheduler(); +#endif + + switch_user(); + /* Reopen log file. If user switch results in access denied, we catch + * it early. + */ + Log_reset(); + + Server_run(); + +#ifdef USE_SHAREDMEMORY_API + Sharedmemory_deinit(); +#endif + + Ban_deinit(); + SSLi_deinit(); + Chan_free(); + Log_free(); + Conf_deinit(); + + if (pidfile != NULL) + unlink(pidfile); + + return 0; + }