X-Git-Url: http://git.code-monkey.de/?a=blobdiff_plain;f=src%2Fmain.c;h=fce997a77a471f4201d3706e107f0e51ac1fee58;hb=c989e4519ccdb068d0897e6255b9f3306e385bac;hp=7bd8a0bfbefdcc2a7e6dadb4a95efbc0744a8582;hpb=0fd109448ce43a6a53866614423463788c278ff6;p=umurmur.git diff --git a/src/main.c b/src/main.c index 7bd8a0b..fce997a 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-2011, Martin Johansson + Copyright (C) 2005-2011, Thorvald Natvig All rights reserved. @@ -29,13 +29,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - #include #include #include #include #include #include +#include +#include #include #include #include @@ -57,26 +58,112 @@ char *bindaddr; void lockfile(const char *pidfile) { - int lfp; + int lfp, flags; char str[16]; - - lfp = open(pidfile, O_RDWR|O_CREAT|O_EXCL, 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); + + /* 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()); write(lfp, str, strlen(str)); /* record pid to lockfile */ - close(lfp); 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"); + Log_info("HUP signal received."); + Log_reset(); break; case SIGTERM: Log_info("TERM signal. Shutting down."); @@ -190,17 +277,28 @@ int main(int argc, char **argv) } } + /* 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) { - Log_init(false); daemonize(); + Log_init(false); if (pidfile != NULL) lockfile(pidfile); - } - else - Log_init(true); - Conf_init(conffile); - + switch_user(); + + /* Reopen log file. If user switch results in access denied, we catch + * it early. + */ + Log_reset(); + } + else Log_init(true); + signal(SIGCHLD, SIG_IGN); /* ignore child */ signal(SIGTSTP, SIG_IGN); /* ignore tty signals */ signal(SIGTTOU, SIG_IGN);