diff options
-rw-r--r-- | common/eurephia_context.h | 7 | ||||
-rw-r--r-- | common/eurephia_log.c | 287 | ||||
-rw-r--r-- | common/eurephia_log.h | 12 | ||||
-rw-r--r-- | eurephiadm/client_context.c | 49 | ||||
-rw-r--r-- | eurephiadm/client_context.h | 2 | ||||
-rw-r--r-- | eurephiadm/eurephiadm.c | 8 | ||||
-rw-r--r-- | plugin/eurephia-auth.c | 6 | ||||
-rw-r--r-- | plugin/eurephia.c | 46 | ||||
-rw-r--r-- | plugin/firewall/eurephiafw.c | 1 |
9 files changed, 287 insertions, 131 deletions
diff --git a/common/eurephia_context.h b/common/eurephia_context.h index 877632c..e825c28 100644 --- a/common/eurephia_context.h +++ b/common/eurephia_context.h @@ -32,8 +32,8 @@ #define EUREPHIASTRUCT_H_ #include <stdio.h> -#include "eurephiadb_struct.h" - +#include <eurephiadb_struct.h> +#include <eurephia_log_struct.h> /** * eurephia context types */ @@ -58,8 +58,7 @@ typedef struct { void *fwcfg; /**< Dummy pointer, if the firewall API is not enabled */ #endif char *server_salt; /**< The in-memory password salt, used for the password cache */ - FILE *log; /**< FILE pointer to the log file */ - int loglevel; /**< Defines the log verbosity, higher number increases log verbosity */ + eurephiaLOG *log; /**< Log context, used by eurephia_log() */ int fatal_error; /**< If this flag is set, the execution should stop immediately */ int context_type; /**< Defines the context type */ } eurephiaCTX; diff --git a/common/eurephia_log.c b/common/eurephia_log.c index 0955aa0..ceff25f 100644 --- a/common/eurephia_log.c +++ b/common/eurephia_log.c @@ -31,34 +31,169 @@ #include <stdio.h> #include <stdarg.h> +#include <syslog.h> #include <string.h> #include <time.h> #include <pthread.h> +#include <assert.h> #include <eurephia_context.h> -#include "eurephia_log.h" +#include <eurephia_log.h> +#include <eurephia_nullsafe.h> /** - * Mapping table for mapping log types (defined in eurephia_log.h) - * to string values + * Maps eurephia log types (priorities) to string values + * + * @param prio eurephia logtype, such as LOG_INFO, LOG_DEBUG, LOG_FATAL, etc + * + * @return String containing the log type/prio */ -const char *erp_logtypes[] = { - "\0", - "-- INFO -- \0", /**< LOG_INFO */ - "-- DEBUG -- \0", /**< LOG_DEBUG */ - "** WARNING ** \0", /**< LOG_WARNING */ - "** ERROR ** \0", /**< LOG_ERROR */ - "** CRITICAL ** \0", /**< LOG_CRITICAL */ - "** - FATAL - ** \0", /**< LOG_FATAL */ - "** * PANIC * ** \0" /**< LOG_PANIC */ +static inline const char *logprio_str(int prio) { + switch( prio ) { + case LOG_INFO: + return "-- INFO -- \0"; + case LOG_DEBUG: + return "-- DEBUG -- \0"; + case LOG_WARNING: + return "** WARNING ** \0"; + case LOG_ERROR: + return "** ERROR ** \0"; + case LOG_CRITICAL: + return "** CRITICAL ** \0"; + case LOG_FATAL: + return "** - FATAL - ** \0"; + case LOG_PANIC: + return "** * PANIC * ** \0"; + default: + return "[[ UNKNOWN ]]\0"; + } +} + + +/** + * Mapping table for eurephia log types to syslog log types + */ +static const int syslog_priority[] = { + -1, + LOG_INFO, /**< LOG_INFO */ + LOG_DEBUG, /**< LOG_DEBUG */ + LOG_WARNING, /**< LOG_WARNING */ + LOG_ERR, /**< LOG_ERROR */ + LOG_CRIT, /**< LOG_CRITICAL */ + LOG_ALERT, /**< LOG_FATAL */ + LOG_EMERG /**< LOG_PANIC */ }; + +/** + * Converts eurephiaLOGTYPE value to a string + * + * @param lt eurephiaLOGTYPE, must be either logFILE or logSYSLOG + * + * @return Returns a static string with log type + */ +static inline const char *logtype_str(eurephiaLOGTYPE lt) { + switch( lt ) { + case logFILE: + return "file\0"; + case logSYSLOG: + return "syslog\0"; + } + return NULL; +} + + +/** + * Converts a string of log destination/facilities to syslog values + * + * @param dest String containing the log destination + * + * @return Returns a syslog compatible value, such as LOG_AUTHPRIV, LOG_LOCAL{0-7}, LOG_USER, etc. + * Unknown types will be set to syslog default, LOG_USER. + * + * @remark The following list will list up facilities which will be ignored and LOG_USER will be used + * instead: LOG_CRON, LOG_FTP, LOG_KERN, LOG_LPR, LOG_MAIL, LOG_NEWS, LOG_SYSLOG, LOG_UUCP. + * + */ +static const int syslog_logdest(const char *dest) { + if( dest == NULL ) { + return LOG_USER; + } + + if( strcasecmp(dest, "auth") == 0 ) { + return LOG_AUTHPRIV; // LOG_AUTH is deprecated, and LOG_AUTHPRIV should be used instead + } else if( strcasecmp(dest, "authpriv") == 0 ) { + return LOG_AUTHPRIV; + } else if( strcasecmp(dest, "daemon") == 0 ) { + return LOG_DAEMON; + } else if( strcasecmp(dest, "local0") == 0 ) { + return LOG_LOCAL0; + } else if( strcasecmp(dest, "local1") == 0 ) { + return LOG_LOCAL1; + } else if( strcasecmp(dest, "local2") == 0 ) { + return LOG_LOCAL2; + } else if( strcasecmp(dest, "local3") == 0 ) { + return LOG_LOCAL3; + } else if( strcasecmp(dest, "local4") == 0 ) { + return LOG_LOCAL4; + } else if( strcasecmp(dest, "local5") == 0 ) { + return LOG_LOCAL5; + } else if( strcasecmp(dest, "local6") == 0 ) { + return LOG_LOCAL6; + } else if( strcasecmp(dest, "local7") == 0 ) { + return LOG_LOCAL7; + } else { + return LOG_USER; + } +} + + /** * POSIX Mutex to avoid simultaneously logging activity from * several threads at the same time */ pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER; + +/** + * Simple function for logging entries to a file with timestamp + * + * @param log FILE pointer to a log file + * @param logdst Log destiation/priority + * @param loglvl Log level of the message + * @param format stdarg, format string + * @param ap stdarg va_list, prepared by va_start() + */ +static void file_log(FILE *log, int logdst, int loglvl, const char *fmt, va_list ap) { + char tstmp_str[200]; + time_t tstmp; + struct tm *loctstmp; + + if( log == NULL ) { + return; + } + + // Get time stamp + memset(&tstmp_str, 0, 200); + tstmp = time(NULL); + loctstmp = localtime(&tstmp); + if( loctstmp != NULL ) { + if( strftime(tstmp_str, 198, "%Y-%m-%d %H:%M:%S %Z", loctstmp) == 0 ) { + snprintf(tstmp_str, 198, "(error getting time stamp string)"); + } + } else { + snprintf(tstmp_str, 198, "(error getting timestamp)"); + } + + // Do the logging + pthread_mutex_lock(&log_mutex); // Block other threads from writing when we write + fprintf(log, "[%s] %s [%i] ", tstmp_str, logprio_str(logdst), loglvl); + vfprintf(log, fmt, ap); + fprintf(log, "\n"); + fflush(log); + pthread_mutex_unlock(&log_mutex); // Unblock other threads +} + /** * Simple log function which writes log data to the log file available in the eurephiaCTX * @@ -72,32 +207,116 @@ pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER; void eurephia_log(eurephiaCTX *ctx, int logdst, int loglvl, const char *fmt, ... ) { // Only log if we have an open log file and which has high enough log level - if( (ctx != NULL) && (ctx->log != NULL) && (ctx->loglevel >= loglvl) ) { + if( (ctx != NULL) && (ctx->log != NULL) && (ctx->log->opened == 1) + && (ctx->log->loglevel >= loglvl) ) { va_list ap; - char tstmp_str[200]; - time_t tstmp; - struct tm *loctstmp; - - // Get time stamp - memset(&tstmp_str, 0, 200); - tstmp = time(NULL); - loctstmp = localtime(&tstmp); - if( loctstmp != NULL ) { - if( strftime(tstmp_str, 198, "%Y-%m-%d %H:%M:%S %Z", loctstmp) == 0 ) { - snprintf(tstmp_str, 198, "(error getting time stamp string)"); - } - } else { - snprintf(tstmp_str, 198, "(error getting timestamp)"); - } va_start(ap, fmt); - pthread_mutex_lock(&log_mutex); // Block other threads from writing when we write - fprintf(ctx->log, "[%s] %s [%i] ", tstmp_str, erp_logtypes[logdst], loglvl); - vfprintf(ctx->log, fmt, ap); - fprintf(ctx->log, "\n"); - fflush(ctx->log); - pthread_mutex_unlock(&log_mutex); // Unblock other threads + switch( ctx->log->logtype ) { + case logFILE: + file_log(ctx->log->logfile, logdst, loglvl, fmt, ap); + break; + case logSYSLOG: + vsyslog(syslog_priority[logdst], fmt, ap); + break; + } va_end(ap); } } + +/** + * Closes an eurephia log context + * + * @param ctx eurephiaCTX containing the log context to be closed + * + */ +void eurephia_log_close(eurephiaCTX *ctx) { + if( (ctx == NULL) || (ctx->log == NULL) ) { + return; + } + + eurephia_log(ctx, LOG_INFO, 2, "Closing %s logging (%s).", + logtype_str(ctx->log->logtype), ctx->log->destination); + if( ctx->log->opened == 1 ) { + switch( ctx->log->logtype ) { + case logFILE: + if( ctx->log->logfile != NULL ) { + fflush(ctx->log->logfile); + fclose(ctx->log->logfile); + } + ctx->log->logfile = NULL; + break; + + case logSYSLOG: + closelog(); + break; + } + ctx->log->opened = 0; + } + free_nullsafe(ctx, ctx->log->destination); + free_nullsafe(ctx, ctx->log); +} + +/** + * Initialises and preapres the log device + * + * @param ctx eurephiaCTX where the log context will be associated + * @param dest Log destination. For can be a file name, "syslog:", "stdout:", "stderr:" or "none:". + * If it is "syslog:" it must continue with a string describing log facility such as + * "syslog:authpriv", "syslog:local0", "syslog:local1", "syslog:user", etc. If the + * facility is unknown, it will default to "user" + * + * @return Returns 1 on success, otherwise 0; + */ +int eurephia_log_init(eurephiaCTX *ctx, const char *dest, int loglevel) { + + assert( (ctx != NULL) && (dest != NULL) ); + + // Create log context + ctx->log = (eurephiaLOG *) malloc_nullsafe(ctx, sizeof(eurephiaLOG)+2); + if( ctx->log == NULL ) { + return 0; + } + + if( strncmp(dest, "syslog:", 7) == 0 ) { + ctx->log->logtype = logSYSLOG; + ctx->log->destination = strdup(dest+7); + } else { + ctx->log->logtype = logFILE; + ctx->log->destination = strdup(dest); + } + if( ctx->log->destination == NULL) { + free_nullsafe(ctx, ctx->log); + return 0; + } + ctx->log->loglevel = loglevel; + + switch( ctx->log->logtype ) { + case logFILE: // Open log file + if( strcmp(dest, "stdout:") == 0 ) { + ctx->log->logfile = stdout; + } else if( strcmp(dest, "stderr:") == 0 ) { + ctx->log->logfile = stderr; + } else if( strcmp(dest, "none:") == 0 ) { + ctx->log->logfile = NULL; + ctx->log->loglevel = 0; + ctx->log->opened = 0; + return 1; + } else if( (ctx->log->logfile = fopen(dest, "aw")) == NULL ) { + fprintf(stderr, "ERROR: Could not open log file: %s\n", ctx->log->destination); + free_nullsafe(ctx, ctx->log->destination); + free_nullsafe(ctx, ctx->log); + return 0; + } + break; + + case logSYSLOG: // Open syslog + openlog("eurephia", LOG_PID, syslog_logdest(ctx->log->destination)); + break; + } + ctx->log->opened = 1; + eurephia_log(ctx, LOG_INFO, 1, "Logging to %s (%s) started", + logtype_str(ctx->log->logtype), ctx->log->destination); + return 1; +} diff --git a/common/eurephia_log.h b/common/eurephia_log.h index 97e58d2..cb83f61 100644 --- a/common/eurephia_log.h +++ b/common/eurephia_log.h @@ -31,16 +31,9 @@ #ifndef EUREPHIA_LOG_H_ #define EUREPHIA_LOG_H_ +#include <eurephia_log_struct.h> #include <eurephia_context.h> -#define LOG_INFO 1 /**< Informational messages. Log level should be < 5 */ -#define LOG_DEBUG 2 /**< Messages intended when debugging. Only for log level > 10 */ -#define LOG_WARNING 3 /**< Input data or processing revealed unexpected data. Log level never > 2*/ -#define LOG_ERROR 4 /**< API errors but not sever, program can continue to run */ -#define LOG_CRITICAL 5 /**< Operation failed and might have been aborted. Log level always 0 */ -#define LOG_FATAL 6 /**< Operation failed and cannot continue. Log level always < 2 */ -#define LOG_PANIC 7 /**< Action failed an program could not continue to run. Log level always 0 */ - #ifdef ENABLE_DEBUG #warning ###### DEBUG LOGGING IS ENABLED - THIS COULD BE A SECURITY ISSUE ###### /** @@ -60,6 +53,9 @@ #warning ## ## #warning ########################################################################################## #endif + +int eurephia_log_init(eurephiaCTX *ctx, const char *dest, int loglvl); +void eurephia_log_close(eurephiaCTX *ctx); void eurephia_log(eurephiaCTX *ctx, int logdst, int loglvl, const char *fmt, ... ); #endif /* !EUREPHIA_LOG_H_ */ diff --git a/eurephiadm/client_context.c b/eurephiadm/client_context.c index aaec995..1a8fc0b 100644 --- a/eurephiadm/client_context.c +++ b/eurephiadm/client_context.c @@ -43,13 +43,13 @@ * Initialises a new eurephiaCTX. This function also initialises the database driver, which must * be configured in the configuration. * - * @param log FILE pointer where to put log data + * @param log String containing log destination * @param loglevel Set the log level (verbosity) * @param cfg eurephiaVALUES pointer to the configuration * * @return Returns a pointer to a eurephiaCTX, otherwise NULL. */ -eurephiaCTX *eurephiaCTX_init(FILE *log, const int loglevel, eurephiaVALUES *cfg) { +eurephiaCTX *eurephiaCTX_init(const char *log, const int loglevel, eurephiaVALUES *cfg) { eurephiaCTX *ctx = NULL; char *dbdriver = NULL, *logfile = NULL; int cfgloglvl = 0; @@ -62,39 +62,21 @@ eurephiaCTX *eurephiaCTX_init(FILE *log, const int loglevel, eurephiaVALUES *cfg ctx = (eurephiaCTX *) malloc_nullsafe(NULL, sizeof(eurephiaCTX)+2); assert(ctx != NULL); - memset(ctx, 0, sizeof(eurephiaCTX)+2); ctx->context_type = ECTX_ADMIN_CONSOLE; // Open log file. Use config file as default if it exists, if not use input param. - logfile = eGet_value(cfg, "log"); + cfgloglvl = ((eGet_value(cfg, "log_level") == NULL) + ? loglevel : atoi_nullsafe(eGet_value(cfg, "log_level"))); + + logfile = eGet_value(cfg, "log"); if( (logfile != NULL) && (log == NULL) ) { - if( strcmp(logfile, "stdout:") == 0 ) { - ctx->log = stdout; - } else if( strcmp(logfile, "stderr:") == 0 ) { - ctx->log = stderr; - } else if( strcmp(logfile, "none:") == 0 ) { - ctx->log = NULL; - } else if( (ctx->log = fopen(logfile, "aw")) == NULL ) { - fprintf(stderr, "ERROR: Could not open log file: %s\n", logfile); - free_nullsafe(NULL, ctx); - return NULL; - } + eurephia_log_init(ctx, logfile, (loglevel > 0 ? loglevel : cfgloglvl)); } else { // If log file is not set in config, use input log parameter. But if // no log file is defined even here, use stderr. If no logging is wanted, it // must be defined as none: in the config file. - ctx->log = (log != NULL ? log : stderr); - } - - // Set log level. Use config file as default if it exists, if not input param defaults. - // But if input param loglevel > 0, then override config file. - // Only set loglevel if logging is enabled. - if( ctx->log != NULL ) { - cfgloglvl = ((eGet_value(cfg, "log_level") == NULL) - ? loglevel : atoi_nullsafe(eGet_value(cfg, "log_level"))); - ctx->loglevel = (loglevel > 0 ? loglevel : cfgloglvl); - } else { - ctx->loglevel = 0; + eurephia_log_init(ctx, (log != NULL ? log : "stderr:"), + (loglevel > 0 ? loglevel : cfgloglvl)); } if( !eDBlink_init(ctx, dbdriver, 2) ) { @@ -125,17 +107,6 @@ void eurephiaCTX_destroy(eurephiaCTX *ctx) { eDBlink_close(ctx); } - if( ctx->log != NULL ) { - fflush(ctx->log); - - // Do not close log file if we're on stdout or stderr - if( (ctx->log != stderr) && (ctx->log != stdout) ) { - eurephia_log(ctx, LOG_INFO, 2, "Closing log file"); - fclose(ctx->log); - } - - ctx->log = NULL; - ctx->loglevel = 0; - } + eurephia_log_close(ctx); free_nullsafe(ctx, ctx); } diff --git a/eurephiadm/client_context.h b/eurephiadm/client_context.h index 56e85ed..ef6f5a4 100644 --- a/eurephiadm/client_context.h +++ b/eurephiadm/client_context.h @@ -31,7 +31,7 @@ #ifndef EUREPHIA_CLIENT_CONTEXT #define EUREPHIA_CLIENT_CONTEXT -eurephiaCTX *eurephiaCTX_init(FILE *log, const int loglevel, eurephiaVALUES *cfg); +eurephiaCTX *eurephiaCTX_init(const char *log, const int loglevel, eurephiaVALUES *cfg); void eurephiaCTX_destroy(eurephiaCTX *ctx); #endif diff --git a/eurephiadm/eurephiadm.c b/eurephiadm/eurephiadm.c index 518f8a5..4209e6a 100644 --- a/eurephiadm/eurephiadm.c +++ b/eurephiadm/eurephiadm.c @@ -327,7 +327,7 @@ char *args2string(int argc, char **argv) { * @return returns 0 on success, otherwise a value > 0 */ int main(int argc, char **argv) { - FILE *logfile = NULL; + char *logfile = NULL; int loglevel = 0; eurephiaCTX *ctx = NULL; eurephiaSESSION *session = NULL; @@ -367,11 +367,7 @@ int main(int argc, char **argv) { return 0; case 'l': - if( (logfile = fopen(optargs[0], "wb")) == NULL ) { - fprintf(stderr, "%s: ERROR :: Could not open log file: %s\n", - basename(argv[0]), optargs[0]); - return 0; - } + logfile = optargs[0]; break; case 'L': diff --git a/plugin/eurephia-auth.c b/plugin/eurephia-auth.c index 3536281..10d9447 100644 --- a/plugin/eurephia-auth.c +++ b/plugin/eurephia-auth.c @@ -189,9 +189,9 @@ OPENVPN_EXPORT int openvpn_plugin_func_v1(openvpn_plugin_handle_t handle, DEBUG(ctx, 10, "openvpn_plugin_func_v1(ctx, %s, ...)", plugin_type_name(type)); #ifdef ENABLE_DEBUG - if( ctx->loglevel >= 30 ) { - dump_env(ctx->log, "ENV: ", envp); - dump_env(ctx->log, "ARG: ", argv); + if( (ctx->log->loglevel >= 30) && (ctx->log->logfile != NULL) ) { + dump_env(ctx->log->logfile, "ENV: ", envp); + dump_env(ctx->log->logfile, "ARG: ", argv); } #endif diff --git a/plugin/eurephia.c b/plugin/eurephia.c index 761ab71..f93ee81 100644 --- a/plugin/eurephia.c +++ b/plugin/eurephia.c @@ -183,26 +183,15 @@ eurephiaCTX *eurephiaInit(const char **argv) ctx->context_type = ECTX_PLUGIN_AUTH; // Open a log file - if( logfile != NULL ) { - if( strcmp(logfile, "openvpn:") == 0 ) { // Let openvpn do the logging - ctx->log = stderr; - } else if( strcmp(logfile, "none:") == 0 ) { // Do not perform any logging - ctx->log = NULL; - } else { // if no hit on these ones,open a file with given name - ctx->log = fopen(logfile, "aw"); - if( ctx->log == NULL ) { - fprintf(stderr, "Could not open eurephia log file: %s\n", argv[1]); - return NULL; - } - } - } else { - // If no logging is given ... log to openvpn: - ctx->log = stderr; + if( (logfile == NULL) || (strcmp(logfile, "openvpn:") == 0) ) { + // If no logfile is given, or openvpn: is given, log to stderr which OpenVPN will + // take care of + eurephia_log_init(ctx, "stderr:", loglvl); + } else { + // If another log file is given, process that + eurephia_log_init(ctx, logfile, loglvl); } - // Set log verbosity - ctx->loglevel = loglvl; - // Load the database driver if( (error == 0) && eDBlink_init(ctx, dbi, 1) ) { // Connect to the database @@ -217,10 +206,8 @@ eurephiaCTX *eurephiaInit(const char **argv) } if( error > 0 ) { - if( ctx->log != NULL ) { - eurephia_log(ctx, LOG_PANIC, 0, "eurephia-auth is not available"); - fclose(ctx->log); - } + eurephia_log(ctx, LOG_PANIC, 0, "eurephia-auth is not available"); + eurephia_log_close(ctx); free_nullsafe(ctx, ctx); return NULL; } @@ -234,7 +221,7 @@ eurephiaCTX *eurephiaInit(const char **argv) free_nullsafe(ctx, ctx->server_salt); eDBdisconnect(ctx); - fclose(ctx->log); + eurephia_log_close(ctx); free_nullsafe(ctx, ctx); return NULL; } @@ -287,18 +274,7 @@ int eurephiaShutdown(eurephiaCTX *ctx) eDBlink_close(ctx); } - if( ctx->log != NULL ) { - fflush(ctx->log); - - // Do not close log file if we're on stdout or stderr - if( (ctx->log != stderr) && (ctx->log != stdout) ) { - eurephia_log(ctx, LOG_INFO, 2, "Closing log file"); - fclose(ctx->log); - } - - ctx->log = NULL; - ctx->loglevel = 0; - } + eurephia_log_close(ctx); memset(ctx->server_salt, 0xff, SIZE_PWDCACHE_SALT+2); free_nullsafe(ctx, ctx->server_salt); diff --git a/plugin/firewall/eurephiafw.c b/plugin/firewall/eurephiafw.c index 0d2cc43..2c6755f 100644 --- a/plugin/firewall/eurephiafw.c +++ b/plugin/firewall/eurephiafw.c @@ -146,7 +146,6 @@ void eFW_StartFirewall(eurephiaCTX *ctx) { shadowctx = (eurephiaCTX *) malloc_nullsafe(ctx, sizeof(eurephiaCTX)+2); assert( shadowctx != NULL ); shadowctx->context_type = ECTX_NO_PRIVILEGES; - shadowctx->loglevel = ctx->loglevel; shadowctx->log = ctx->log; (*ctx->fwcfg).thrdata.ctx = shadowctx; |