File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ipguard / system.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 21:59:41 2012 UTC (12 years, 8 months ago) by misho
Branches: ipguard, MAIN
CVS tags: v1_04p3, v1_04p0, v1_04, HEAD
ipguard

/*  system.c
 *
 * Copyright (c) 2010 SeaD <sead at deep.perm.ru>
 *
 * 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 <pwd.h>
#include <signal.h>
#include <paths.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifdef __linux__
# include <time.h>
#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;
    }
}

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>