/* system.c * * Copyright (c) 2010 SeaD * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: system.c,v 1.1.1.1 2012/02/21 21:59:41 misho Exp $ * */ #include #include #include #include #include #include #ifdef __linux__ # include #endif /* __linux__ */ #include "ipguard.h" static int SIGNAL = 0; static FILE *log_fp = NULL, *pid_fp = NULL; void exit_ipguard(int reason) { if (verbose) { snprintf(s, 64, "Exit on reason %d (pid: %u)", reason, getpid()); log_str(NOTICE, s, ""); } packet_destroy(); pid_unlink(); log_close(); exit(reason); } void sig_init(void) { if (signal(SIGINT, sig_func) == SIG_ERR) { log_str(ERROR, "signal(SIGINT):", strerror(errno)); exit(EXIT_FAILURE); } if (signal(SIGTERM, sig_func) == SIG_ERR) { log_str(ERROR, "signal(SIGTERM):", strerror(errno)); exit(EXIT_FAILURE); } if (signal(SIGHUP, sig_func) == SIG_ERR) { log_str(ERROR, "signal(SIGHUP):", strerror(errno)); exit(EXIT_FAILURE); } if (signal(SIGUSR1, sig_func) == SIG_ERR) { log_str(ERROR, "signal(SIGUSR1):", strerror(errno)); exit(EXIT_FAILURE); } if (signal(SIGUSR2, sig_func) == SIG_ERR) { log_str(ERROR, "signal(SIGUSR2):", strerror(errno)); exit(EXIT_FAILURE); } } void sig_func(int signal) { if (verbose) { snprintf(s, 4, "%d", signal); log_str(NOTICE, "SIGNAL received", s); } SIGNAL = signal; if ((SIGNAL == SIGINT) || (SIGNAL == SIGTERM)) exit_ipguard(SIGNAL); } void sig_catch(void) { switch (SIGNAL) { case SIGHUP: ethers_reinit(); if (!getuid()) log_reopen(); SIGNAL = 0; break; case SIGUSR1: pair_dump(); if (buffer_num) buffer_dump(); stat_dump(); SIGNAL = 0; break; case SIGUSR2: buffer_dump2ethers(); SIGNAL = 0; break; } } void log_open(void) { if (!(log_fp = fopen(log_name, "a"))) { fprintf(stderr, "fopen(%s): %s\n", log_name, strerror(errno)); exit(EXIT_FAILURE); } } void log_str(int pri, char *ent, char *err) { char p[10]; switch (pri) { case ERROR: strncpy(p, "error", 10); break; case WARNING: strncpy(p, "warning", 10); break; case NOTICE: strncpy(p, "notice", 10); break; case INFO: strncpy(p, "info", 10); break; default: strncpy(p, "unknown", 10); break; } if (debug > 1) fprintf(stderr, "%s ", time_get()); if (debug) fprintf(stderr, "%s %s\n", ent, err); fprintf(log_fp, "%s %s %s %s\n", time_get(), p, ent, err); fflush(log_fp); } void log_close(void) { if (fclose(log_fp)) { fprintf(stderr, "fclose(%s): %s\n", log_name, strerror(errno)); } } void log_reopen(void) { log_close(); log_open(); log_str(NOTICE, "Log file reopened:", log_name); } void pid_check(void) { struct stat ps; int pid = 0; if (stat(pid_name, &ps) == -1) { if (errno == ENOENT) return; else { snprintf(s, 128, "stat(%s):", pid_name); log_str(ERROR, s, strerror(errno)); exit(EXIT_FAILURE); } } else { if (!(pid_fp = fopen(pid_name, "r"))) { snprintf(s, 128, "fopen(%s):", pid_name); log_str(WARNING, s, strerror(errno)); } fscanf(pid_fp, "%d", &pid); fclose(pid_fp); if (pid) { if (kill(pid, 0)) { snprintf(s, 64, "Removing stale pid: %u", pid); log_str(WARNING, s, ""); pid_unlink(); } else { snprintf(s, 64, "Already running, pid: %u", pid); log_str(ERROR, s, ""); exit(EXIT_FAILURE); } } else { snprintf(s, 64, "Wrong pid file found: %s", pid_name); log_str(ERROR, s, ""); exit(EXIT_FAILURE); } } } void pid_creat(void) { pid_check(); if (!(pid_fp = fopen(pid_name, "w"))) { snprintf(s, 128, "fopen(%s):", pid_name); log_str(ERROR, s, strerror(errno)); exit(EXIT_FAILURE); } fprintf(pid_fp, "%d\n", getpid()); fclose(pid_fp); } void pid_unlink(void) { if (unlink(pid_name) == -1) { snprintf(s, 128, "unlink(%s):", pid_name); log_str(NOTICE, s, strerror(errno)); } } void daemonize(void) { int pid, null; if ((pid = fork()) == -1) { log_str(ERROR, "fork():", strerror(errno)); exit(EXIT_FAILURE); } else if (pid > 0) exit(EXIT_SUCCESS); if ((null = open(_PATH_DEVNULL, O_RDWR)) == -1) { log_str(ERROR, "open(_PATH_DEVNULL):", strerror(errno)); exit(EXIT_FAILURE); } if (dup2(null, 0) == -1) { log_str(ERROR, "dup2(STDIN):", strerror(errno)); exit(EXIT_FAILURE); } if (dup2(null, 1) == -1) { log_str(ERROR, "dup2(STDOUT):", strerror(errno)); exit(EXIT_FAILURE); } if (dup2(null, 2) == -1) { log_str(ERROR, "dup2(STDERR):", strerror(errno)); exit(EXIT_FAILURE); } if (setsid() == -1) { log_str(ERROR, "setsid():", strerror(errno)); exit(EXIT_FAILURE); } if (chdir("/") == -1) { log_str(ERROR, "chdir(/):", strerror(errno)); exit(EXIT_FAILURE); } } void set_user(void) { struct passwd *pw; int uid = 0, gid = 0; if ((pw = getpwnam(suser))) { uid = pw->pw_uid; gid = pw->pw_gid; } else if (!(uid = atoi(suser))) { pw = getpwuid(uid); gid = pw->pw_gid; } else { log_str(ERROR, "Invalid user", suser); exit(EXIT_FAILURE); } if (setgid(gid) == -1) { log_str(ERROR, "setgid():", strerror(errno)); exit(EXIT_FAILURE); } if (setuid(uid) == -1) { log_str(ERROR, "setuid():", strerror(errno)); exit(EXIT_FAILURE); } snprintf(s, 128, "%u/%u", uid, gid); if (verbose) log_str(NOTICE, "Running as uid/gid:", s); } void mac_rand(char *mac) { char c[] = " "; register int n; for (n = 0; n < 18; n++) if (mac[n] == 'x') { snprintf(c, 2, "%1x", rand() % 16); mac[n] = c[0]; } } void mac_regen(char *mac) { static time_t count = 0; time_t t; char c[] = " "; register int n; if ((t = time(&t)) < count) return; count = t + fake_regen; if (debug > 1) fprintf(stderr, "FAKE REGEN: pre %-17s ", mac); for (n = 0; n < 18; n++) if ((mac[n] >= '0' && mac[n] <= '9') || (mac[n] >= 'A' && mac[n] <= 'F') || (mac[n] >= 'a' && mac[n] <= 'f')) { snprintf(c, 2, "%1x", rand() % 16); mac[n] = c[0]; } if (debug > 1) fprintf(stderr, "new %-17s\n", mac); } char *time_get(void) { static char cur_time[16]; time_t t; t = time(&t); strncpy(cur_time, (char *) ctime(&t) + 4, 15); cur_time[15] = '\0'; return cur_time; } void ethers_stat(void) { struct stat es; static time_t ethers_mtime = 0, count = 0; time_t t; if ((t = time(&t)) < count) return; count = t + ethers_update; if (stat(ethers_name, &es) == -1) { snprintf(s, 128, "stat(%s):", ethers_name); log_str(WARNING, s, strerror(errno)); return; } if (!ethers_mtime) ethers_mtime = es.st_mtime; if (ethers_mtime < es.st_mtime) { ethers_reinit(); ethers_mtime = es.st_mtime; } }