|
@@ -1,918 +0,0 @@
|
|
|
-#define _GNU_SOURCE
|
|
|
-#include <stdlib.h>
|
|
|
-#include <stdint.h>
|
|
|
-#include <stdio.h>
|
|
|
-#include <string.h>
|
|
|
-#include <assert.h>
|
|
|
-#include <signal.h>
|
|
|
-#include <syslog.h>
|
|
|
-#include <unistd.h>
|
|
|
-#include <errno.h>
|
|
|
-#include <sys/types.h>
|
|
|
-#include <sys/stat.h>
|
|
|
-#include <fcntl.h>
|
|
|
-#include <getopt.h>
|
|
|
-#include <sys/socket.h>
|
|
|
-#include <sys/un.h>
|
|
|
-#include <sys/fsuid.h>
|
|
|
-#include <sys/wait.h>
|
|
|
-#include <poll.h>
|
|
|
-#include <time.h>
|
|
|
-
|
|
|
-#include <faux/faux.h>
|
|
|
-#include <faux/str.h>
|
|
|
-#include <faux/ini.h>
|
|
|
-#include <faux/log.h>
|
|
|
-#include <faux/sched.h>
|
|
|
-#include <faux/sysdb.h>
|
|
|
-#include <faux/net.h>
|
|
|
-#include <faux/list.h>
|
|
|
-#include <faux/conv.h>
|
|
|
-#include <faux/file.h>
|
|
|
-#include <crsp.h>
|
|
|
-#include <crsp_cdp.h>
|
|
|
-#include <crsp_hl.h>
|
|
|
-
|
|
|
-#ifndef VERSION
|
|
|
-#define VERSION "1.0.0"
|
|
|
-#endif
|
|
|
-
|
|
|
-#define CRSD_LOG_NAME "crsd"
|
|
|
-#define CRSD_DEFAULT_PIDFILE "/var/run/crsd.pid"
|
|
|
-#define CRSD_DEFAULT_CFGFILE "/etc/crs/crsd.conf"
|
|
|
-#define CRSD_DEFAULT_FETCH_INTERVAL 120
|
|
|
-#define CRSD_DEFAULT_FETCH_MARGIN 50
|
|
|
-#define CRSD_DEFAULT_FETCH_TIMEOUT 60
|
|
|
-#define CRSD_DEFAULT_CRL_MAX_SIZE 50000000ul
|
|
|
-#define CRSD_DEFAULT_CRL_STORAGE_MAX_SIZE 5000000000ul
|
|
|
-#define CRSD_DEFAULT_ROOTCERT_DIR "/etc/config/ike/ipsec.d/rootcerts"
|
|
|
-#define CRSD_DEFAULT_CACERT_DIR "/etc/config/ike/ipsec.d/cacerts"
|
|
|
-#define CRSD_DEFAULT_CERT_DIR "/etc/config/ike/ipsec.d/certs"
|
|
|
-#define CRSD_DEFAULT_OCSPCERT_DIR "/etc/config/ike/ipsec.d/ocspcerts"
|
|
|
-#define CRSD_DEFAULT_CRL_DIR "/etc/config/ike/ipsec.d/crls"
|
|
|
-#define CRSD_DEFAULT_KEY_DIR "/etc/config/ike/ipsec.d/private"
|
|
|
-#define CRSD_DEFAULT_P10_DIR "/etc/config/ike/ipsec.d/reqs"
|
|
|
-#define CRSD_DEFAULT_SECRETS_FILE "/etc/config/ike/ipsec.secrets"
|
|
|
-
|
|
|
-// Signal handlers
|
|
|
-static volatile int sigterm = 0; // Exit if 1
|
|
|
-static void sighandler(int signo);
|
|
|
-static volatile int sighup = 0; // Re-read config file
|
|
|
-static void sighup_handler(int signo);
|
|
|
-static volatile int sigchld = 0; // Child execution is finished
|
|
|
-static void sigchld_handler(int signo);
|
|
|
-
|
|
|
-// Options and config file
|
|
|
-static void help(int status, const char *argv0);
|
|
|
-static struct options *opts_init(void);
|
|
|
-static void opts_free(struct options *opts);
|
|
|
-static int opts_parse(int argc, char *argv[], struct options *opts);
|
|
|
-static int opts_show(struct options *opts);
|
|
|
-static int config_parse(const char *cfgfile, struct options *opts);
|
|
|
-
|
|
|
-
|
|
|
-// Local syslog function
|
|
|
-bool_t verbose = BOOL_FALSE;
|
|
|
-bool_t silent = BOOL_FALSE;
|
|
|
-static void lsyslog(int priority, const char *format, ...)
|
|
|
-{
|
|
|
- va_list ap;
|
|
|
-
|
|
|
- if (silent)
|
|
|
- return;
|
|
|
-
|
|
|
- if (!verbose && (LOG_DEBUG == priority))
|
|
|
- return;
|
|
|
-
|
|
|
- // Calculate buffer size
|
|
|
- va_start(ap, format);
|
|
|
- vsyslog(priority, format, ap);
|
|
|
- va_end(ap);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/** @brief Command line and config file options
|
|
|
- */
|
|
|
-struct options {
|
|
|
- char *pidfile;
|
|
|
- char *cfgfile;
|
|
|
- char *unix_socket_path;
|
|
|
- bool_t cfgfile_userdefined;
|
|
|
- bool_t foreground; // Don't daemonize
|
|
|
- bool_t verbose;
|
|
|
- bool_t silent;
|
|
|
- bool_t check;
|
|
|
- int log_facility;
|
|
|
- char *uid_str;
|
|
|
- char *gid_str;
|
|
|
- uid_t uid;
|
|
|
- gid_t gid;
|
|
|
- long int fetch_interval;
|
|
|
- unsigned char fetch_margin;
|
|
|
- long int fetch_timeout;
|
|
|
- unsigned long int crl_max_size;
|
|
|
- unsigned long int crl_storage_max_size;
|
|
|
- char *rootcert_dir;
|
|
|
- char *cacert_dir;
|
|
|
- char *cert_dir;
|
|
|
- char *ocspcert_dir;
|
|
|
- char *crl_dir;
|
|
|
- char *key_dir;
|
|
|
- char *p10_dir;
|
|
|
- char *secrets_file;
|
|
|
-};
|
|
|
-
|
|
|
-// Network
|
|
|
-static int create_listen_sock(const char *path, uid_t uid, gid_t gid);
|
|
|
-
|
|
|
-
|
|
|
-/** @brief Main function
|
|
|
- */
|
|
|
-int main(int argc, char **argv)
|
|
|
-{
|
|
|
- int retval = -1;
|
|
|
- struct options *opts = NULL;
|
|
|
- int pidfd = -1;
|
|
|
- int logmask = 0;
|
|
|
- int logoptions = 0;
|
|
|
-
|
|
|
- // Event scheduler
|
|
|
- faux_sched_t *sched = NULL;
|
|
|
-
|
|
|
- // Network
|
|
|
- int listen_sock = -1;
|
|
|
- faux_pollfd_t *fds = NULL;
|
|
|
-
|
|
|
- // Signal vars
|
|
|
- struct sigaction sig_act = {};
|
|
|
- sigset_t sig_set = {};
|
|
|
- sigset_t orig_sig_set = {}; // Saved signal mask
|
|
|
-
|
|
|
- // Parse command line options
|
|
|
- opts = opts_init();
|
|
|
- if (opts_parse(argc, argv, opts))
|
|
|
- goto err;
|
|
|
-
|
|
|
- // Initialize syslog
|
|
|
- logoptions = LOG_CONS;
|
|
|
- if (opts->foreground)
|
|
|
- logoptions |= LOG_PERROR;
|
|
|
- openlog(CRSD_LOG_NAME, logoptions, opts->log_facility);
|
|
|
- if (!opts->verbose) {
|
|
|
- logmask = setlogmask(0);
|
|
|
- logmask = logmask & ~LOG_MASK(LOG_DEBUG);
|
|
|
- setlogmask(logmask);
|
|
|
- }
|
|
|
-
|
|
|
- // Parse config file
|
|
|
- lsyslog(LOG_DEBUG, "Parse config file: %s\n", opts->cfgfile);
|
|
|
- if (!access(opts->cfgfile, R_OK)) {
|
|
|
- if (config_parse(opts->cfgfile, opts))
|
|
|
- goto err;
|
|
|
- } else if (opts->cfgfile_userdefined) {
|
|
|
- // User defined config must be found
|
|
|
- fprintf(stderr, "Error: Can't find config file %s\n",
|
|
|
- opts->cfgfile);
|
|
|
- goto err;
|
|
|
- }
|
|
|
- if (opts->check) { // Check only. Return 0 if config file is ok.
|
|
|
- retval = 0;
|
|
|
- goto err;
|
|
|
- }
|
|
|
-
|
|
|
- // DEBUG: Show options
|
|
|
- opts_show(opts);
|
|
|
-
|
|
|
- // Set crsp lib global var for debug
|
|
|
- if (opts->verbose)
|
|
|
- crsp_debug = 1;
|
|
|
-
|
|
|
- lsyslog(LOG_INFO, "Start daemon.\n");
|
|
|
-
|
|
|
- // Fork the daemon
|
|
|
- if (!opts->foreground) {
|
|
|
- // Daemonize
|
|
|
- lsyslog(LOG_DEBUG, "Daemonize\n");
|
|
|
- if (daemon(0, 0) < 0) {
|
|
|
- lsyslog(LOG_ERR, "Can't daemonize\n");
|
|
|
- goto err;
|
|
|
- }
|
|
|
-
|
|
|
- // Write pidfile
|
|
|
- lsyslog(LOG_DEBUG, "Write PID file: %s\n", opts->pidfile);
|
|
|
- if ((pidfd = open(opts->pidfile,
|
|
|
- O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
|
|
|
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
|
|
|
- lsyslog(LOG_WARNING, "Can't open pidfile %s: %s\n",
|
|
|
- opts->pidfile, strerror(errno));
|
|
|
- } else {
|
|
|
- char str[20];
|
|
|
- snprintf(str, sizeof(str), "%u\n", getpid());
|
|
|
- str[sizeof(str) - 1] = '\0';
|
|
|
- if (write(pidfd, str, strlen(str)) < 0)
|
|
|
- lsyslog(LOG_WARNING, "Can't write to %s: %s\n",
|
|
|
- opts->pidfile, strerror(errno));
|
|
|
- close(pidfd);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Network initialization
|
|
|
- lsyslog(LOG_DEBUG, "Create listen socket: %s\n", opts->unix_socket_path);
|
|
|
- listen_sock = create_listen_sock(opts->unix_socket_path,
|
|
|
- opts->uid, opts->gid);
|
|
|
- if (listen_sock < 0)
|
|
|
- goto err;
|
|
|
-
|
|
|
- // Change UID/GID
|
|
|
- if (opts->uid != getuid()) {
|
|
|
- lsyslog(LOG_DEBUG, "Change UID: %s\n", opts->uid_str ? opts->uid_str : "");
|
|
|
- setfsuid(opts->uid);
|
|
|
- if (setresuid(opts->uid, opts->uid, opts->uid) < 0) {
|
|
|
- lsyslog(LOG_ERR, "Can't change user: %s", strerror(errno));
|
|
|
- goto err;
|
|
|
- }
|
|
|
- }
|
|
|
- if (opts->gid != getgid()) {
|
|
|
- lsyslog(LOG_DEBUG, "Change GID: %s\n", opts->gid_str ? opts->gid_str : "");
|
|
|
- if (setresgid(opts->gid, opts->gid, opts->gid) < 0 ) {
|
|
|
- lsyslog(LOG_ERR, "Can't change group: %s", strerror(errno));
|
|
|
- goto err;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Set signal handler
|
|
|
- lsyslog(LOG_DEBUG, "Set signal handlers\n");
|
|
|
- sigemptyset(&sig_set);
|
|
|
- sigaddset(&sig_set, SIGTERM);
|
|
|
- sigaddset(&sig_set, SIGINT);
|
|
|
- sigaddset(&sig_set, SIGQUIT);
|
|
|
-
|
|
|
- sig_act.sa_flags = 0;
|
|
|
- sig_act.sa_mask = sig_set;
|
|
|
- sig_act.sa_handler = &sighandler;
|
|
|
- sigaction(SIGTERM, &sig_act, NULL);
|
|
|
- sigaction(SIGINT, &sig_act, NULL);
|
|
|
- sigaction(SIGQUIT, &sig_act, NULL);
|
|
|
-
|
|
|
- // SIGHUP handler
|
|
|
- sigemptyset(&sig_set);
|
|
|
- sigaddset(&sig_set, SIGHUP);
|
|
|
-
|
|
|
- sig_act.sa_flags = 0;
|
|
|
- sig_act.sa_mask = sig_set;
|
|
|
- sig_act.sa_handler = &sighup_handler;
|
|
|
- sigaction(SIGHUP, &sig_act, NULL);
|
|
|
-
|
|
|
- // SIGCHLD handler
|
|
|
- sigemptyset(&sig_set);
|
|
|
- sigaddset(&sig_set, SIGCHLD);
|
|
|
-
|
|
|
- sig_act.sa_flags = 0;
|
|
|
- sig_act.sa_mask = sig_set;
|
|
|
- sig_act.sa_handler = &sigchld_handler;
|
|
|
- sigaction(SIGCHLD, &sig_act, NULL);
|
|
|
-
|
|
|
- // The struct pollfd vector for ppoll()
|
|
|
- fds = faux_pollfd_new();
|
|
|
- if (!fds) {
|
|
|
- lsyslog(LOG_ERR, "Can't init pollfd vector");
|
|
|
- goto err;
|
|
|
- }
|
|
|
- // Add listen socket to pollfds vector
|
|
|
- faux_pollfd_add(fds, listen_sock, POLLIN);
|
|
|
-
|
|
|
- // Block signals to prevent race conditions while loop and ppoll()
|
|
|
- // Catch signals while ppoll() only
|
|
|
- sigemptyset(&sig_set);
|
|
|
- sigaddset(&sig_set, SIGTERM);
|
|
|
- sigaddset(&sig_set, SIGINT);
|
|
|
- sigaddset(&sig_set, SIGQUIT);
|
|
|
- sigaddset(&sig_set, SIGHUP);
|
|
|
- sigaddset(&sig_set, SIGCHLD);
|
|
|
- sigprocmask(SIG_BLOCK, &sig_set, &orig_sig_set);
|
|
|
-
|
|
|
- // Main loop
|
|
|
- while (!sigterm) {
|
|
|
- int sn = 0;
|
|
|
- struct timespec *timeout = NULL;
|
|
|
- struct timespec next_interval = {};
|
|
|
- faux_pollfd_iterator_t pollfd_iter;
|
|
|
- struct pollfd *pollfd = NULL;
|
|
|
- pid_t pid = -1;
|
|
|
-
|
|
|
- // Re-read config file on SIGHUP
|
|
|
- if (sighup) {
|
|
|
- if (access(opts->cfgfile, R_OK) == 0) {
|
|
|
- lsyslog(LOG_INFO, "Re-reading config file\n");
|
|
|
- if (config_parse(opts->cfgfile, opts) < 0)
|
|
|
- lsyslog(LOG_ERR, "Error while config file parsing.\n");
|
|
|
- reschedule_all(sched, cdp_db,
|
|
|
- opts->fetch_interval,
|
|
|
- opts->fetch_margin);
|
|
|
- } else if (opts->cfgfile_userdefined) {
|
|
|
- lsyslog(LOG_ERR, "Can't find config file.\n");
|
|
|
- }
|
|
|
- sighup = 0;
|
|
|
- }
|
|
|
-
|
|
|
- // Non-blocking wait for all children
|
|
|
- while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) {
|
|
|
- lsyslog(LOG_DEBUG, "Exit child process %d\n", pid);
|
|
|
- }
|
|
|
- sigchld = 0;
|
|
|
-
|
|
|
- // Find out timeout interval
|
|
|
- if (faux_sched_next_interval(sched, &next_interval) < 0) {
|
|
|
- timeout = NULL;
|
|
|
- } else {
|
|
|
- timeout = &next_interval;
|
|
|
- lsyslog(LOG_DEBUG, "Next interval: %ld\n", timeout->tv_sec);
|
|
|
- }
|
|
|
-
|
|
|
- // Wait for events
|
|
|
- sn = ppoll(faux_pollfd_vector(fds), faux_pollfd_len(fds), timeout, &orig_sig_set);
|
|
|
- if (sn < 0) {
|
|
|
- if ((EAGAIN == errno) || (EINTR == errno))
|
|
|
- continue;
|
|
|
- lsyslog(LOG_ERR, "Error while select(): %s\n", strerror(errno));
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- // Timeout (Scheduled event)
|
|
|
- if (0 == sn) {
|
|
|
- int id = 0; // Event idenftifier
|
|
|
- void *data = NULL; // Event data
|
|
|
-
|
|
|
- // Some scheduled events
|
|
|
- while(faux_sched_pop(sched, &id, &data) == 0) {
|
|
|
- cdp_t *cdp = (cdp_t *)data;
|
|
|
- download_args_t download_args = {};
|
|
|
- // Now we have only one type of event - it's
|
|
|
- // a scheduled CRL downloading
|
|
|
- lsyslog(LOG_DEBUG, "sched: Update event for %s\n", cdp_uri(cdp));
|
|
|
- download_args.cdp = cdp;
|
|
|
- download_args.opts = opts;
|
|
|
- fork_action(download_crl, (void *)&download_args);
|
|
|
- }
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- // Get data via socket
|
|
|
- faux_pollfd_init_iterator(fds, &pollfd_iter);
|
|
|
- while ((pollfd = faux_pollfd_each_active(fds, &pollfd_iter))) {
|
|
|
- crsp_msg_t *req = NULL;
|
|
|
- crsp_msg_t *ack = NULL;
|
|
|
- faux_net_t *net = NULL;
|
|
|
- int fd = pollfd->fd;
|
|
|
- crsp_recv_e recv_status = CRSP_RECV_OK;
|
|
|
-
|
|
|
- // Listen socket
|
|
|
- if (fd == listen_sock) {
|
|
|
- int new_conn = -1;
|
|
|
- new_conn = accept(listen_sock, NULL, NULL);
|
|
|
- if (new_conn < 0)
|
|
|
- continue;
|
|
|
- faux_pollfd_add(fds, new_conn, POLLIN);
|
|
|
- lsyslog(LOG_DEBUG, "New connection %d\n", new_conn);
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- // If it's not a listen socket then we have received
|
|
|
- // a message from client.
|
|
|
- net = faux_net_new();
|
|
|
- faux_net_set_fd(net, fd);
|
|
|
- // Get message
|
|
|
- req = crsp_msg_recv(net, &recv_status);
|
|
|
-
|
|
|
- // Prepare empty answer structure
|
|
|
- ack = crsp_msg_new();
|
|
|
-
|
|
|
- // Compose answer
|
|
|
- if (req) {
|
|
|
- msg_cb_f *handler =
|
|
|
- msg_handler[crsp_msg_get_cmd(req)];
|
|
|
- crsp_msg_t *answer = NULL;
|
|
|
-
|
|
|
- // Callback function fills the answer by
|
|
|
- // real data
|
|
|
- if (handler) {
|
|
|
- msg_cb_args_t args = {};
|
|
|
-
|
|
|
- args.cdp_db = cdp_db;
|
|
|
- args.sched = sched;
|
|
|
- args.opts = opts;
|
|
|
- args.credio = credio;
|
|
|
- args.net = net;
|
|
|
- answer = handler(req, ack, &args);
|
|
|
- if (!answer) { // Some local problem
|
|
|
- crsp_msg_set_cmd(ack, CRSP_CMD_ERROR);
|
|
|
- crsp_msg_set_status(ack, CRSP_STATUS_ERROR);
|
|
|
- }
|
|
|
- cdp_db_debug(cdp_db);
|
|
|
- // If there is no handler for this commnand just
|
|
|
- // return "unknown/unsupported command" message.
|
|
|
- } else {
|
|
|
- crsp_msg_set_cmd(ack, CRSP_CMD_ERROR);
|
|
|
- crsp_msg_set_status(ack, CRSP_STATUS_UNSUPPORTED);
|
|
|
- }
|
|
|
-
|
|
|
- // Some error while receiving
|
|
|
- } else {
|
|
|
- crsp_msg_set_cmd(ack, CRSP_CMD_ERROR);
|
|
|
- switch(recv_status) {
|
|
|
- case CRSP_RECV_OK: // Some system problem
|
|
|
- crsp_msg_set_status(ack, CRSP_STATUS_ERROR);
|
|
|
- break;
|
|
|
- default: // Classified problem
|
|
|
- // Now error codes of status is
|
|
|
- // equal to receive statuses. It can be
|
|
|
- // changed later.
|
|
|
- crsp_msg_set_status(ack, recv_status);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Send ACK
|
|
|
- crsp_msg_send(ack, net);
|
|
|
- crsp_msg_free(ack);
|
|
|
-
|
|
|
- crsp_msg_free(req);
|
|
|
- close(fd);
|
|
|
- faux_net_free(net);
|
|
|
- faux_pollfd_del_by_fd(fds, fd);
|
|
|
- lsyslog(LOG_DEBUG, "Close connection %d\n", fd);
|
|
|
- }
|
|
|
-
|
|
|
- } // Main loop end
|
|
|
-
|
|
|
-
|
|
|
- retval = 0;
|
|
|
-
|
|
|
-err:
|
|
|
- lsyslog(LOG_DEBUG, "Cleanup.\n");
|
|
|
-
|
|
|
- sigprocmask(SIG_BLOCK, &orig_sig_set, NULL);
|
|
|
- faux_pollfd_free(fds);
|
|
|
- faux_sched_free(sched);
|
|
|
-
|
|
|
- // Close listen socket
|
|
|
- if (listen_sock >= 0)
|
|
|
- close(listen_sock);
|
|
|
-
|
|
|
- // Clean CDP database
|
|
|
- cdp_db_free(cdp_db);
|
|
|
-
|
|
|
- // Remove pidfile
|
|
|
- if (pidfd >= 0) {
|
|
|
- if (unlink(opts->pidfile) < 0) {
|
|
|
- lsyslog(LOG_ERR, "Can't remove pid-file %s: %s\n",
|
|
|
- opts->pidfile, strerror(errno));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Crypto cleanup
|
|
|
- pgst_credio_free(&credio);
|
|
|
- pgst_cossl_free(&ossl);
|
|
|
-
|
|
|
- // Free command line options
|
|
|
- opts_free(opts);
|
|
|
- lsyslog(LOG_INFO, "Stop daemon.\n");
|
|
|
-
|
|
|
- return retval;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/** @brief Create listen socket
|
|
|
- */
|
|
|
-static int create_listen_sock(const char *path, uid_t uid, gid_t gid)
|
|
|
-{
|
|
|
- int sock = -1;
|
|
|
- int opt = 1;
|
|
|
- struct sockaddr_un laddr = {};
|
|
|
-// mode_t mode = 0660;
|
|
|
-
|
|
|
- if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
|
|
|
- lsyslog(LOG_ERR, "Cannot create socket: %s\n", strerror(errno));
|
|
|
- goto error;
|
|
|
- }
|
|
|
- if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
|
|
|
- lsyslog(LOG_ERR, "Can't set socket options: %s\n", strerror(errno));
|
|
|
- goto error;
|
|
|
- }
|
|
|
- laddr.sun_family = AF_UNIX;
|
|
|
- strncpy(laddr.sun_path, path, USOCK_PATH_MAX);
|
|
|
- laddr.sun_path[USOCK_PATH_MAX - 1] = '\0';
|
|
|
-
|
|
|
- unlink(path);
|
|
|
-
|
|
|
- if (bind(sock, (struct sockaddr *)&laddr, sizeof(laddr))) {
|
|
|
- lsyslog(LOG_ERR, "Can't bind socket: %s\n", strerror(errno));
|
|
|
- goto err2;
|
|
|
- }
|
|
|
-
|
|
|
- if (uid != getuid() || gid != getgid()) {
|
|
|
- if (chown(path, uid, gid)) {
|
|
|
- lsyslog(LOG_ERR, "Can't chown socket: %s\n", strerror(errno));
|
|
|
- goto err2;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-// if (chmod(path, mode)) {
|
|
|
-// lsyslog(LOG_ERR, "Can't chmod socket: %s\n", strerror(errno));
|
|
|
-// goto err2;
|
|
|
-// }
|
|
|
-
|
|
|
- if (listen(sock, 64)) {
|
|
|
- lsyslog(LOG_ERR, "Can't listen socket: %s\n", strerror(errno));
|
|
|
- goto err2;
|
|
|
- }
|
|
|
-
|
|
|
- return sock;
|
|
|
-
|
|
|
-err2:
|
|
|
- unlink(path);
|
|
|
-error:
|
|
|
- if (sock != -1)
|
|
|
- close(sock);
|
|
|
- return -1;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/** @brief Signal handler for temination signals (like SIGTERM, SIGINT, ...)
|
|
|
- */
|
|
|
-static void sighandler(int signo)
|
|
|
-{
|
|
|
- sigterm = 1;
|
|
|
- signo = signo; // Happy compiler
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/** @brief Re-read config file on SIGHUP
|
|
|
- */
|
|
|
-static void sighup_handler(int signo)
|
|
|
-{
|
|
|
- sighup = 1;
|
|
|
- signo = signo; // Happy compiler
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/** @brief Child was finished
|
|
|
- */
|
|
|
-static void sigchld_handler(int signo)
|
|
|
-{
|
|
|
- sigchld = 1;
|
|
|
- signo = signo; // Happy compiler
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/** @brief Initialize option structure by defaults
|
|
|
- */
|
|
|
-static struct options *opts_init(void)
|
|
|
-{
|
|
|
- struct options *opts = NULL;
|
|
|
-
|
|
|
- opts = faux_zmalloc(sizeof(*opts));
|
|
|
- assert(opts);
|
|
|
-
|
|
|
- // Initialize
|
|
|
- opts->pidfile = faux_str_dup(CRSD_DEFAULT_PIDFILE);
|
|
|
- opts->cfgfile = faux_str_dup(CRSD_DEFAULT_CFGFILE);
|
|
|
- opts->unix_socket_path = faux_str_dup(CRSD_DEFAULT_UNIX_SOCKET_PATH);
|
|
|
- opts->cfgfile_userdefined = BOOL_FALSE;
|
|
|
- opts->foreground = BOOL_FALSE; // Daemonize by default
|
|
|
- opts->verbose = BOOL_FALSE;
|
|
|
- opts->silent = BOOL_FALSE;
|
|
|
- opts->check = BOOL_FALSE;
|
|
|
- opts->log_facility = LOG_DAEMON;
|
|
|
- opts->uid = getuid();
|
|
|
- opts->gid = getgid();
|
|
|
- opts->uid_str = faux_sysdb_name_by_uid(opts->uid);
|
|
|
- opts->gid_str = faux_sysdb_name_by_gid(opts->gid);
|
|
|
- opts->fetch_interval = CRSD_DEFAULT_FETCH_INTERVAL;
|
|
|
- opts->fetch_margin = CRSD_DEFAULT_FETCH_MARGIN;
|
|
|
- opts->fetch_timeout = CRSD_DEFAULT_FETCH_TIMEOUT;
|
|
|
- opts->crl_max_size = CRSD_DEFAULT_CRL_MAX_SIZE;
|
|
|
- opts->crl_storage_max_size = CRSD_DEFAULT_CRL_STORAGE_MAX_SIZE;
|
|
|
- opts->rootcert_dir = faux_str_dup(CRSD_DEFAULT_ROOTCERT_DIR);
|
|
|
- opts->cacert_dir = faux_str_dup(CRSD_DEFAULT_CACERT_DIR);
|
|
|
- opts->cert_dir = faux_str_dup(CRSD_DEFAULT_CERT_DIR);
|
|
|
- opts->ocspcert_dir = faux_str_dup(CRSD_DEFAULT_OCSPCERT_DIR);
|
|
|
- opts->crl_dir = faux_str_dup(CRSD_DEFAULT_CRL_DIR);
|
|
|
- opts->key_dir = faux_str_dup(CRSD_DEFAULT_KEY_DIR);
|
|
|
- opts->p10_dir = faux_str_dup(CRSD_DEFAULT_P10_DIR);
|
|
|
- opts->secrets_file = faux_str_dup(CRSD_DEFAULT_SECRETS_FILE);
|
|
|
-
|
|
|
- return opts;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/** @brief Free options structure
|
|
|
- */
|
|
|
-static void opts_free(struct options *opts)
|
|
|
-{
|
|
|
- faux_str_free(opts->pidfile);
|
|
|
- faux_str_free(opts->cfgfile);
|
|
|
- faux_str_free(opts->unix_socket_path);
|
|
|
- faux_str_free(opts->uid_str);
|
|
|
- faux_str_free(opts->gid_str);
|
|
|
- faux_str_free(opts->rootcert_dir);
|
|
|
- faux_str_free(opts->cacert_dir);
|
|
|
- faux_str_free(opts->cert_dir);
|
|
|
- faux_str_free(opts->ocspcert_dir);
|
|
|
- faux_str_free(opts->crl_dir);
|
|
|
- faux_str_free(opts->key_dir);
|
|
|
- faux_str_free(opts->p10_dir);
|
|
|
- faux_str_free(opts->secrets_file);
|
|
|
- faux_free(opts);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/** @brief Parse command line options
|
|
|
- */
|
|
|
-static int opts_parse(int argc, char *argv[], struct options *opts)
|
|
|
-{
|
|
|
- static const char *shortopts = "hp:c:fl:vsk";
|
|
|
- static const struct option longopts[] = {
|
|
|
- {"help", 0, NULL, 'h'},
|
|
|
- {"pid", 1, NULL, 'p'},
|
|
|
- {"conf", 1, NULL, 'c'},
|
|
|
- {"foreground", 0, NULL, 'f'},
|
|
|
- {"verbose", 0, NULL, 'v'},
|
|
|
- {"silent", 0, NULL, 's'},
|
|
|
- {"check", 0, NULL, 'k'},
|
|
|
- {"facility", 1, NULL, 'l'},
|
|
|
- {NULL, 0, NULL, 0}
|
|
|
- };
|
|
|
-
|
|
|
- optind = 1;
|
|
|
- while(1) {
|
|
|
- int opt = 0;
|
|
|
-
|
|
|
- opt = getopt_long(argc, argv, shortopts, longopts, NULL);
|
|
|
- if (-1 == opt)
|
|
|
- break;
|
|
|
- switch (opt) {
|
|
|
- case 'p':
|
|
|
- faux_str_free(opts->pidfile);
|
|
|
- opts->pidfile = faux_str_dup(optarg);
|
|
|
- break;
|
|
|
- case 'c':
|
|
|
- faux_str_free(opts->cfgfile);
|
|
|
- opts->cfgfile = faux_str_dup(optarg);
|
|
|
- opts->cfgfile_userdefined = BOOL_TRUE;
|
|
|
- break;
|
|
|
- case 'f':
|
|
|
- opts->foreground = BOOL_TRUE;
|
|
|
- break;
|
|
|
- case 'v':
|
|
|
- opts->verbose = BOOL_TRUE;
|
|
|
- break;
|
|
|
- case 's':
|
|
|
- opts->silent = BOOL_TRUE;
|
|
|
- break;
|
|
|
- case 'k':
|
|
|
- opts->check = BOOL_TRUE;
|
|
|
- break;
|
|
|
- case 'l':
|
|
|
- if (faux_log_facility_id(optarg, &(opts->log_facility))) {
|
|
|
- fprintf(stderr, "Error: Illegal syslog facility %s.\n", optarg);
|
|
|
- _exit(-1);
|
|
|
- }
|
|
|
- break;
|
|
|
- case 'h':
|
|
|
- help(0, argv[0]);
|
|
|
- _exit(0);
|
|
|
- break;
|
|
|
- default:
|
|
|
- help(-1, argv[0]);
|
|
|
- _exit(-1);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-/** @brief Print help message
|
|
|
- */
|
|
|
-static void help(int status, const char *argv0)
|
|
|
-{
|
|
|
- const char *name = NULL;
|
|
|
-
|
|
|
- if (!argv0)
|
|
|
- return;
|
|
|
-
|
|
|
- // Find the basename
|
|
|
- name = strrchr(argv0, '/');
|
|
|
- if (name)
|
|
|
- name++;
|
|
|
- else
|
|
|
- name = argv0;
|
|
|
-
|
|
|
- if (status != 0) {
|
|
|
- fprintf(stderr, "Try `%s -h' for more information.\n",
|
|
|
- name);
|
|
|
- } else {
|
|
|
- printf("Version : %s\n", VERSION);
|
|
|
- printf("Usage : %s [options]\n", name);
|
|
|
- printf("Certificate Revocation Service Daemon\n");
|
|
|
- printf("Options :\n");
|
|
|
- printf("\t-h, --help Print this help.\n");
|
|
|
- printf("\t-f, --foreground Don't daemonize.\n");
|
|
|
- printf("\t-v, --verbose Be verbose.\n");
|
|
|
- printf("\t-s, --silent Be silent.\n");
|
|
|
- printf("\t-k, --check Check config only and exit.\n");
|
|
|
- printf("\t-p <path>, --pid=<path> File to save daemon's PID to ("
|
|
|
- CRSD_DEFAULT_PIDFILE ").\n");
|
|
|
- printf("\t-c <path>, --conf=<path> Config file ("
|
|
|
- CRSD_DEFAULT_CFGFILE ").\n");
|
|
|
- printf("\t-l, --facility Syslog facility (DAEMON).\n");
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/** @brief Parse config file
|
|
|
- */
|
|
|
-static int config_parse(const char *cfgfile, struct options *opts)
|
|
|
-{
|
|
|
- faux_ini_t *ini = NULL;
|
|
|
- const char *tmp = NULL;
|
|
|
-
|
|
|
- ini = faux_ini_new();
|
|
|
- assert(ini);
|
|
|
- if (!ini)
|
|
|
- return -1;
|
|
|
- if (faux_ini_parse_file(ini, cfgfile)) {
|
|
|
- lsyslog(LOG_ERR, "Can't parse config file: %s\n", cfgfile);
|
|
|
- faux_ini_free(ini);
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- if ((tmp = faux_ini_find(ini, "UnixSocketPath"))) {
|
|
|
- faux_str_free(opts->unix_socket_path);
|
|
|
- opts->unix_socket_path = faux_str_dup(tmp);
|
|
|
- }
|
|
|
-
|
|
|
- if ((tmp = faux_ini_find(ini, "UID"))) {
|
|
|
- faux_str_free(opts->uid_str);
|
|
|
- opts->uid_str = faux_str_dup(tmp);
|
|
|
- if (faux_sysdb_uid_by_name(opts->uid_str, &opts->uid) < 0) {
|
|
|
- lsyslog(LOG_ERR, "Unknown user: %s\n", opts->uid_str);
|
|
|
- faux_ini_free(ini);
|
|
|
- return -1; // Unknown user
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if ((tmp = faux_ini_find(ini, "GID"))) {
|
|
|
- faux_str_free(opts->gid_str);
|
|
|
- opts->gid_str = faux_str_dup(tmp);
|
|
|
- if (faux_sysdb_gid_by_name(opts->gid_str, &opts->gid)) {
|
|
|
- lsyslog(LOG_ERR, "Unknown group: %s\n", opts->gid_str);
|
|
|
- faux_ini_free(ini);
|
|
|
- return -1; // Unknown group
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if ((tmp = faux_ini_find(ini, "FetchInterval"))) {
|
|
|
- if (faux_conv_atol(tmp, &opts->fetch_interval, 10) < 0) {
|
|
|
- lsyslog(LOG_ERR, "Illegal FetchInterval: %s\n", tmp);
|
|
|
- faux_ini_free(ini);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- if (opts->fetch_interval < 0) {
|
|
|
- lsyslog(LOG_ERR, "FetchInterval can't be less than zero: %s\n", tmp);
|
|
|
- faux_ini_free(ini);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if ((tmp = faux_ini_find(ini, "FetchMargin"))) {
|
|
|
- if (faux_conv_atouc(tmp, &opts->fetch_margin, 10) < 0) {
|
|
|
- lsyslog(LOG_ERR, "Illegal FetchMargin: %s\n", tmp);
|
|
|
- faux_ini_free(ini);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- if (opts->fetch_margin > 100) { // Value in percents
|
|
|
- lsyslog(LOG_ERR, "FetchMargin (in percents) can't be greater than 100: %s\n", tmp);
|
|
|
- faux_ini_free(ini);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if ((tmp = faux_ini_find(ini, "FetchTimeout"))) {
|
|
|
- if (faux_conv_atol(tmp, &opts->fetch_timeout, 10) < 0) {
|
|
|
- lsyslog(LOG_ERR, "Illegal FetchTimeout: %s\n", tmp);
|
|
|
- faux_ini_free(ini);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- if (opts->fetch_timeout < 0) {
|
|
|
- lsyslog(LOG_ERR, "FetchTimeout can't be less than zero: %s\n", tmp);
|
|
|
- faux_ini_free(ini);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- if (opts->fetch_timeout > opts->fetch_interval) {
|
|
|
- lsyslog(LOG_ERR, "FetchTimeout can't be greater than FetchInterval: %s\n", tmp);
|
|
|
- faux_ini_free(ini);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if ((tmp = faux_ini_find(ini, "CRLMaxSize"))) {
|
|
|
- if (faux_conv_atoul(tmp, &opts->crl_max_size, 10) < 0) {
|
|
|
- lsyslog(LOG_ERR, "Illegal CRLMaxSize: %s\n", tmp);
|
|
|
- faux_ini_free(ini);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- if (opts->crl_max_size > CRSD_DEFAULT_CRL_MAX_SIZE) {
|
|
|
- lsyslog(LOG_ERR, "CRLMaxSize can't be greater than %lu: %s\n",
|
|
|
- CRSD_DEFAULT_CRL_MAX_SIZE, tmp);
|
|
|
- faux_ini_free(ini);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if ((tmp = faux_ini_find(ini, "CRLStorageMaxSize"))) {
|
|
|
- if (faux_conv_atoul(tmp, &opts->crl_storage_max_size, 10) < 0) {
|
|
|
- lsyslog(LOG_ERR, "Illegal CRLStorageMaxSize: %s\n", tmp);
|
|
|
- faux_ini_free(ini);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if ((tmp = faux_ini_find(ini, "RootCertDir"))) {
|
|
|
- faux_str_free(opts->rootcert_dir);
|
|
|
- opts->rootcert_dir = faux_str_dup(tmp);
|
|
|
- }
|
|
|
-
|
|
|
- if ((tmp = faux_ini_find(ini, "CACertDir"))) {
|
|
|
- faux_str_free(opts->cacert_dir);
|
|
|
- opts->cacert_dir = faux_str_dup(tmp);
|
|
|
- }
|
|
|
-
|
|
|
- if ((tmp = faux_ini_find(ini, "CertDir"))) {
|
|
|
- faux_str_free(opts->cert_dir);
|
|
|
- opts->cert_dir = faux_str_dup(tmp);
|
|
|
- }
|
|
|
-
|
|
|
- if ((tmp = faux_ini_find(ini, "OCSPCertDir"))) {
|
|
|
- faux_str_free(opts->ocspcert_dir);
|
|
|
- opts->ocspcert_dir = faux_str_dup(tmp);
|
|
|
- }
|
|
|
-
|
|
|
- if ((tmp = faux_ini_find(ini, "CRLDir"))) {
|
|
|
- faux_str_free(opts->crl_dir);
|
|
|
- opts->crl_dir = faux_str_dup(tmp);
|
|
|
- }
|
|
|
-
|
|
|
- if ((tmp = faux_ini_find(ini, "KeyDir"))) {
|
|
|
- faux_str_free(opts->key_dir);
|
|
|
- opts->key_dir = faux_str_dup(tmp);
|
|
|
- }
|
|
|
-
|
|
|
- if ((tmp = faux_ini_find(ini, "P10Dir"))) {
|
|
|
- faux_str_free(opts->p10_dir);
|
|
|
- opts->p10_dir = faux_str_dup(tmp);
|
|
|
- }
|
|
|
-
|
|
|
- if ((tmp = faux_ini_find(ini, "SecretsFile"))) {
|
|
|
- faux_str_free(opts->secrets_file);
|
|
|
- opts->secrets_file = faux_str_dup(tmp);
|
|
|
- }
|
|
|
-
|
|
|
- faux_ini_free(ini);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/** @brief Show options. For debug purposes.
|
|
|
- */
|
|
|
-static int opts_show(struct options *opts)
|
|
|
-{
|
|
|
- assert(opts);
|
|
|
- if (!opts)
|
|
|
- return -1;
|
|
|
-
|
|
|
- lsyslog(LOG_DEBUG, "opts: Foreground = %s\n", opts->foreground ? "true" : "false");
|
|
|
- lsyslog(LOG_DEBUG, "opts: Verbose = %s\n", opts->verbose ? "true" : "false");
|
|
|
- lsyslog(LOG_DEBUG, "opts: LogFacility = %s\n", faux_log_facility_str(opts->log_facility));
|
|
|
- lsyslog(LOG_DEBUG, "opts: PIDPath = %s\n", opts->pidfile);
|
|
|
- lsyslog(LOG_DEBUG, "opts: ConfigPath = %s\n", opts->cfgfile);
|
|
|
- lsyslog(LOG_DEBUG, "opts: UnixSocketPath = %s\n", opts->unix_socket_path);
|
|
|
- lsyslog(LOG_DEBUG, "opts: UID = %s\n", opts->uid_str ? opts->uid_str : "");
|
|
|
- lsyslog(LOG_DEBUG, "opts: GID = %s\n", opts->gid_str ? opts->gid_str : "");
|
|
|
- lsyslog(LOG_DEBUG, "opts: FetchInterval = %ld sec\n", opts->fetch_interval);
|
|
|
- lsyslog(LOG_DEBUG, "opts: FetchMargin = %u %% \n", opts->fetch_margin);
|
|
|
- lsyslog(LOG_DEBUG, "opts: FetchTimeout = %ld sec\n", opts->fetch_timeout);
|
|
|
- lsyslog(LOG_DEBUG, "opts: CRLMaxSize = %ld bytes\n", opts->crl_max_size);
|
|
|
- lsyslog(LOG_DEBUG, "opts: CRLStorageMaxSize = %ld bytes\n", opts->crl_storage_max_size);
|
|
|
- lsyslog(LOG_DEBUG, "opts: RootCertDir = %s\n", opts->rootcert_dir);
|
|
|
- lsyslog(LOG_DEBUG, "opts: CACertDir = %s\n", opts->cacert_dir);
|
|
|
- lsyslog(LOG_DEBUG, "opts: CertDir = %s\n", opts->cert_dir);
|
|
|
- lsyslog(LOG_DEBUG, "opts: OCSPCertDir = %s\n", opts->ocspcert_dir);
|
|
|
- lsyslog(LOG_DEBUG, "opts: CRLDir = %s\n", opts->crl_dir);
|
|
|
- lsyslog(LOG_DEBUG, "opts: KeyDir = %s\n", opts->key_dir);
|
|
|
- lsyslog(LOG_DEBUG, "opts: P10Dir = %s\n", opts->p10_dir);
|
|
|
- lsyslog(LOG_DEBUG, "opts: SecretsFile = %s\n", opts->secrets_file);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|