diff --git a/configure.ac b/configure.ac index 596e8e4c..6031cf0a 100644 --- a/configure.ac +++ b/configure.ac @@ -85,7 +85,7 @@ AC_HEADER_STDC AC_HEADER_TIME AC_HEADER_RESOLV -AC_CHECK_HEADERS([ctype.h endian.h errno.h netdb.h net/ethernet.h netinet/ether.h netinet/ip_icmp.h netinet/in.h netinet/ip.h netinet/tcp.h netinet/udp.h stdint.h stdlib.h string.h strings.h sys/byteorder.h sys/endian.h sys/ethernet.h sys/socket.h sys/stat.h sys/time.h termios.h unistd.h]) +AC_CHECK_HEADERS([ctype.h endian.h errno.h locale.h netdb.h net/ethernet.h netinet/ether.h netinet/ip_icmp.h netinet/in.h netinet/ip.h netinet/tcp.h netinet/udp.h stdint.h stdlib.h string.h strings.h sys/byteorder.h sys/endian.h sys/ethernet.h sys/socket.h sys/stat.h sys/time.h termios.h unistd.h]) # Type checks. # diff --git a/server/config_init.c b/server/config_init.c index dc663d66..893b92c8 100644 --- a/server/config_init.c +++ b/server/config_init.c @@ -210,21 +210,49 @@ parse_config_file(fko_srv_options_t *opts, char *config_file) static void validate_options(fko_srv_options_t *opts) { + char tmp_path[MAX_PATH_LEN]; + /* If a HOSTNAME was specified in the config file, set the opts->hostname * value to it. */ if(opts->config[CONF_HOSTNAME] != NULL && opts->config[CONF_HOSTNAME][0] != '\0') strlcpy(opts->hostname, opts->config[CONF_HOSTNAME], MAX_HOSTNAME_LEN); - /* If the pid and digest cache files where not set in the config file or - * via command-line, then grab the defaults. + /* If no conf dir is set in the config file, use the default. */ + if(opts->config[CONF_FWKNOP_CONF_DIR] == NULL) + set_config_entry(opts, CONF_FWKNOP_CONF_DIR, DEF_CONF_DIR); + + /* If the pid and digest cache files where not set in the config file or + * via command-line, then grab the defaults. Start with RUN_DIR as the + * files may depend on that. + */ + if(opts->config[CONF_FWKNOP_RUN_DIR] == NULL) + set_config_entry(opts, CONF_FWKNOP_RUN_DIR, DEF_RUN_DIR); + if(opts->config[CONF_FWKNOP_PID_FILE] == NULL) - set_config_entry(opts, CONF_FWKNOP_PID_FILE, DEF_PID_FILE); + { + strlcpy(tmp_path, opts->config[CONF_FWKNOP_RUN_DIR], MAX_PATH_LEN); + + if(tmp_path[strlen(tmp_path)-1] != '/') + strlcat(tmp_path, "/", MAX_PATH_LEN); + + strlcat(tmp_path, DEF_PID_FILENAME, MAX_PATH_LEN); + + set_config_entry(opts, CONF_FWKNOP_PID_FILE, tmp_path); + } if(opts->config[CONF_DIGEST_FILE] == NULL) - set_config_entry(opts, CONF_DIGEST_FILE, DEF_DIGEST_CACHE); + { + strlcpy(tmp_path, opts->config[CONF_FWKNOP_RUN_DIR], MAX_PATH_LEN); + if(tmp_path[strlen(tmp_path)-1] != '/') + strlcat(tmp_path, "/", MAX_PATH_LEN); + + strlcat(tmp_path, DEF_DIGEST_CACHE_FILENAME, MAX_PATH_LEN); + + set_config_entry(opts, CONF_DIGEST_FILE, tmp_path); + } /* If log facility and default identity where not set in the config file, * fall back to defaults. @@ -284,6 +312,11 @@ config_init(fko_srv_options_t *opts, int argc, char **argv) if(gethostname(opts->hostname, MAX_HOSTNAME_LEN-1) < 0) strcpy(opts->hostname, "UNKNOWN"); + /* Set the conf hostname entry here in case it is not set in the conf + * file. + */ + set_config_entry(opts, CONF_HOSTNAME, opts->hostname); + /* In case this is a re-config. */ optind = 0; @@ -428,7 +461,7 @@ config_init(fko_srv_options_t *opts, int argc, char **argv) opts->status = 1; break; case 'v': - opts->verbose = 1; + opts->verbose++; break; case 'V': fprintf(stdout, "fwknopd server %s\n", MY_VERSION); @@ -466,10 +499,6 @@ dump_config(fko_srv_options_t *opts) ); fprintf(stderr, "\n"); - - fprintf(stderr, "Hostname is set to '%s'.\n", opts->hostname); - - fprintf(stderr, "\n"); } /* Print usage message... diff --git a/server/fwknopd.c b/server/fwknopd.c index 944b7b2f..6e582d5d 100644 --- a/server/fwknopd.c +++ b/server/fwknopd.c @@ -34,6 +34,8 @@ /* Prototypes */ +static void check_dir_path(const char *path, const char *path_name, unsigned char use_basename); +static int make_dir_path(const char *path); static void daemonize_process(fko_srv_options_t *opts); static int write_pid_file(fko_srv_options_t *opts); static pid_t get_running_pid(fko_srv_options_t *opts); @@ -44,6 +46,7 @@ main(int argc, char **argv) fko_ctx_t ctx; int res, last_sig, rpdb_count; char *spa_data, *version; + char *locale; char access_buf[MAX_LINE_LEN]; pid_t old_pid; @@ -131,6 +134,40 @@ main(int argc, char **argv) */ init_logging(&opts); +#if HAVE_LOCALE_H + /* Set the locale if specified. + */ + if(opts.config[CONF_LOCALE] != NULL) + { + locale = setlocale(LC_ALL, opts.config[CONF_LOCALE]); + + if(locale == NULL) + { + log_msg(LOG_ERR|LOG_STDERR, + "WARNING: Unable to set locale to %s.", + opts.config[CONF_LOCALE] + ); + } + else + { + if(opts.verbose) + log_msg(LOG_ERR|LOG_STDERR, + "Locale set to %s.", opts.config[CONF_LOCALE] + ); + } + } +#endif + + /* Make sure we have a valid run dir and path leading to digest file + * in case it configured to be somewhere other than the run dir. + */ + check_dir_path((const char *)opts.config[CONF_FWKNOP_RUN_DIR], "Run", 0); + check_dir_path((const char *)opts.config[CONF_DIGEST_FILE], "Run", 1); + + /* If we are a new process (just being started), proceed with normal + * startp. Otherwise, we are here as a result of a signal sent to an + * existing process and we want to restart. + */ if(get_running_pid(&opts) != getpid()) { /* If foreground mode is not set, the fork off and become a daemon. @@ -164,8 +201,8 @@ main(int argc, char **argv) log_msg(LOG_INFO, "Re-starting %s", MY_NAME); } - dump_config(&opts); - + /* We only support pcap capture at this point. + */ if((strncasecmp(opts.config[CONF_AUTH_MODE], "pcap", 4)) != 0) { log_msg(LOG_ERR|LOG_STDERR, @@ -174,11 +211,22 @@ main(int argc, char **argv) exit(EXIT_FAILURE); } - /* Initialize the digest cache (replay attack detection dbm). - */ - rpdb_count = replay_db_init(&opts); + if(opts.verbose > 1) + dump_config(&opts); -fprintf(stderr, "RPDB Count: %i\n", rpdb_count); + /* Initialize the digest cache (replay attack detection dbm) + * if so configured. + */ + if(strncasecmp(opts.config[CONF_ENABLE_DIGEST_PERSISTENCE], "Y", 1) == 0) + { + rpdb_count = replay_db_init(&opts); + + if(opts.verbose) + log_msg(LOG_ERR|LOG_STDERR, + "Using Digest Cache: '%s' (entry count = %i)", + opts.config[CONF_DIGEST_FILE], rpdb_count + ); + } /* Intiate pcap capture mode... */ @@ -227,6 +275,145 @@ fprintf(stderr, "RPDB Count: %i\n", rpdb_count); return(0); } +/* Ensure the specified directory exists. If not, create it or die. +*/ +static void +check_dir_path(const char *filepath, const char *fp_desc, unsigned char use_basename) +{ + struct stat st; + int res; + char tmp_path[MAX_PATH_LEN]; + char *ndx; + + /* + * FIXME: We shouldn't use a hard-coded dir-separator here. + */ + /* But first make sure we are using an absolute path. + */ + if(*filepath != '/') + { + log_msg(LOG_ERR|LOG_STDERR, + "Configured %s directory (%s) is not an absolute path.", fp_desc, filepath + ); + exit(EXIT_FAILURE); + } + + /* If this is a file path that we want to use only the basename, strip + * the trailing filename here. + */ + if(use_basename && ((ndx = strrchr(filepath, '/')) != NULL)) + strlcpy(tmp_path, filepath, (ndx-filepath)+1); + else + strcpy(tmp_path, filepath); + + /* At this point, we should make the path is more than just "/". + * If it is not, silently return. + */ + if(strlen(tmp_path) < 2) + return; + + /* Make sure we have a valid directory. + */ + res = stat(tmp_path, &st); + if(res != 0) + { + if(errno == ENOENT) + { + log_msg(LOG_WARNING|LOG_STDERR, + "%s directory: %s does not exist. Attempting to create it.", fp_desc, tmp_path + ); + + /* Directory does not exist, so attempt to create it. + */ + res = make_dir_path(tmp_path); + if(res != 0) + { + log_msg(LOG_ERR|LOG_STDERR, + "Unable to create %s directory: %s (error: %i)", fp_desc, tmp_path, errno + ); + exit(EXIT_FAILURE); + } + + log_msg(LOG_ERR|LOG_STDERR, + "Successfully created %s directory: %s", fp_desc, tmp_path + ); + } + else + { + log_msg(LOG_ERR|LOG_STDERR, + "Stat of %s returned error %i", tmp_path, errno + ); + exit(EXIT_FAILURE); + } + } + else + { + /* It is a file, but is it a directory? + */ + if(! S_ISDIR(st.st_mode)) + { + log_msg(LOG_ERR|LOG_STDERR, + "Specified %s directory: %s is NOT a directory\n\n", fp_desc, tmp_path + ); + exit(EXIT_FAILURE); + } + } +} + +static int +make_dir_path(const char *run_dir) +{ + struct stat st; + int res, len; + char tmp_path[MAX_PATH_LEN]; + char *ndx; + + strlcpy(tmp_path, run_dir, MAX_PATH_LEN); + + len = strlen(tmp_path); + + /* Strip any trailing dir sep char. + */ + if(tmp_path[len-1] == '/') + tmp_path[len-1] = '\0'; + + for(ndx = tmp_path+1; *ndx; ndx++) + { + if(*ndx == '/') + { + *ndx = '\0'; + + /* Stat this part of the path to see if it is a valid directory. + * If it does not exist, attempt to create it. If it does, and + * it is a directory, go on. Otherwise, any other error cause it + * to bail. + */ + if(stat(tmp_path, &st) != 0) + { + if(errno == ENOENT) + res = mkdir(tmp_path, S_IRWXU); + + if(res != 0) + return res; + } + + if(! S_ISDIR(st.st_mode)) + { + log_msg(LOG_ERR|LOG_STDERR, + "Component: %s of %s is NOT a directory\n\n", tmp_path, run_dir + ); + return(ENOTDIR); + } + + *ndx = '/'; + } + } + + res = mkdir(tmp_path, S_IRWXU); + + return(res); +} + /* Become a daemon: fork(), start a new session, chdir "/", * and close unneeded standard filehandles. */ diff --git a/server/fwknopd.h b/server/fwknopd.h index 562a1031..daa941cf 100644 --- a/server/fwknopd.h +++ b/server/fwknopd.h @@ -32,6 +32,10 @@ #include #include +#if HAVE_LOCALE_H + #include +#endif + /* If the flock flags are not defined at this point, we take the liberty * of defining them here. */ diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index d0dbf6c7..eb6e1e2e 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -28,6 +28,8 @@ #include "common.h" +#include + #if HAVE_LIBPCAP #include #endif @@ -47,8 +49,9 @@ /* Our default config directory is based on SYSCONFDIR as set by the * configure script. */ - #define DEF_CONF_DIR SYSCONFDIR"/fwknop" + #define DEF_CONF_DIR SYSCONFDIR"/"PACKAGE_NAME #endif + #define DEF_CONFIG_FILE DEF_CONF_DIR"/"MY_NAME".conf" #define DEF_ACCESS_FILE DEF_CONF_DIR"/access.conf" @@ -56,11 +59,11 @@ /* Our default run directory is based on LOCALSTATEDIR as set by the * configure script. This is where we put the PID and digest cache files. */ - #define DEF_RUN_DIR SYSRUNDIR"/run/fwknop" + #define DEF_RUN_DIR SYSRUNDIR"/run/"PACKAGE_NAME #endif -#define DEF_PID_FILE DEF_RUN_DIR"/"MY_NAME".pid" -#define DEF_DIGEST_CACHE DEF_RUN_DIR"/digest.cache" +#define DEF_PID_FILENAME MY_NAME".pid" +#define DEF_DIGEST_CACHE_FILENAME "digest.cache" #define DEF_INTERFACE "eth0" @@ -154,9 +157,9 @@ enum { //CONF_IPT_SNAT_ACCESS, //CONF_IPT_MASQUERADE_ACCESS, //CONF_FWKNOP_DIR, - //CONF_FWKNOP_RUN_DIR, + CONF_FWKNOP_RUN_DIR, //CONF_FWKNOP_MOD_DIR, - //CONF_FWKNOP_CONF_DIR, + CONF_FWKNOP_CONF_DIR, //CONF_FWKNOP_ERR_DIR, //CONF_ACCESS_CONF, CONF_FWKNOP_PID_FILE, @@ -237,9 +240,9 @@ static char *config_map[NUMBER_OF_CONFIG_ENTRIES] = { //"IPT_SNAT_ACCESS", //"IPT_MASQUERADE_ACCESS", //"FWKNOP_DIR", - //"FWKNOP_RUN_DIR", + "FWKNOP_RUN_DIR", //"FWKNOP_MOD_DIR", - //"FWKNOP_CONF_DIR", + "FWKNOP_CONF_DIR", //"FWKNOP_ERR_DIR", //"ACCESS_CONF", "FWKNOP_PID_FILE",