void _lml_handle_signal_if_needed(void) { int signo; if ( ! got_signal ) return; signo = got_signal; got_signal = 0; #if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) if ( signo == SIGQUIT || signo == SIGUSR1 ) { handle_sigquit(); return; } #endif server_close(); if ( config.lml_client ) prelude_client_destroy(config.lml_client, PRELUDE_CLIENT_EXIT_STATUS_FAILURE); prelude_deinit(); #if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) if ( signo == SIGHUP ) { prelude_log(PRELUDE_LOG_WARN, "signal %d received, restarting (%s).\n", signo, get_restart_string()); handle_sighup(); } #endif prelude_log(PRELUDE_LOG_WARN, "signal %d received, terminating prelude-lml.\n", signo); exit(2); }
static int _charset_convert(lml_charset_t *lc, const char *in, size_t inlen, char **out, size_t *outlen) { char *target; size_t maxlen; UErrorCode status = U_ZERO_ERROR; maxlen = lc->max_char_size * inlen; if ( maxlen < inlen || maxlen + 1 < maxlen ) return -1; *out = target = malloc(maxlen + 1); if ( ! *out ) { prelude_log(PRELUDE_LOG_ERR, "ICU: failed allocating %lu bytes.\n", maxlen); return -1; } ucnv_convertEx(lc->to, lc->from, &target, *out + maxlen + 1, &in, in + inlen, NULL, NULL, NULL, NULL, 0, TRUE, &status); if ( U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING ) { prelude_log(PRELUDE_LOG_ERR, "ICU: failed converting input to UTF-8: %s.\n", u_errorName(status)); free(*out); return -1; } *outlen = target - *out; return 0; }
/** * prelude_daemonize: * @lockfile: Filename to a lockfile. * * Puts caller in background. * If @lockfile is not NULL, a lock for this program is created. * * The lockfile is automatically unlinked on exit. * * Returns: 0 on success, -1 if an error occured. */ int prelude_daemonize(const char *lockfile) { pid_t pid; int fd = 0, ret, i; if ( lockfile ) { ret = get_absolute_filename(lockfile); if ( ret < 0 ) return ret; } #if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__ prelude_log(PRELUDE_LOG_ERR, "Daemonize call unsupported in this environment.\n"); pid = getpid(); #else pid = fork(); if ( pid < 0 ) return prelude_error_from_errno(errno); else if ( pid ) _exit(0); #endif if ( lockfile ) { fd = lockfile_get_exclusive(slockfile); if ( fd < 0 ) return fd; ret = lockfile_write_pid(fd, getpid()); if ( ret < 0 ) return ret; } #if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) setsid(); ret = chdir("/"); if ( ret < 0 ) prelude_log(PRELUDE_LOG_ERR, "could not change working directory to '/': %s.\n", strerror(errno)); umask(0); fd = open("/dev/null", O_RDWR); if ( fd < 0 ) return prelude_error_from_errno(errno); for ( i = 0; i <= 2; i++ ) { do { ret = dup2(fd, i); } while ( ret < 0 && errno == EINTR ); if ( ret < 0 ) return prelude_error_from_errno(errno); } close(fd); #endif return 0; }
static int handle_connection(server_generic_t *server) { int ret, client; server_generic_client_t *cdata; cdata = calloc(1, server->clientlen); if ( ! cdata ) { prelude_log(PRELUDE_LOG_ERR, "memory exhausted.\n"); return -1; } client = accept_connection(server, cdata); if ( client < 0 ) { free(cdata); return -1; } ret = setup_client_socket(server, cdata, client); if ( ret < 0 ) { free(cdata); close(client); return -1; } ret = server_generic_process_requests(server, cdata); if ( ret < 0 ) { prelude_log(PRELUDE_LOG_ERR, "queueing client FD for server logic processing failed.\n"); prelude_io_close(cdata->fd); prelude_io_destroy(cdata->fd); free(cdata); return -1; } return 0; }
/* * Only called if the memory dump of the file was modified, * will write the new content to filename 'filename'. */ static int sync_and_free_file_content(config_t *cfg) { FILE *fd; unsigned int i; size_t ret, len; fd = fopen(cfg->filename, "w"); if ( ! fd ) return prelude_error_verbose(prelude_error_code_from_errno(errno), "could not open '%s' for writing: %s", cfg->filename, strerror(errno)); for ( i = 0; i < cfg->elements; i++ ) { len = strlen(cfg->content[i]); ret = fwrite(cfg->content[i], 1, len, fd); if ( ret != len && ferror(fd) ) prelude_log(PRELUDE_LOG_ERR, "error writing content to '%s': %s", cfg->filename, strerror(errno)); if ( i + 1 != cfg->elements ) { ret = fwrite("\n", 1, 1, fd); if ( ret != 1 && ferror(fd) ) prelude_log(PRELUDE_LOG_ERR, "error writing content to '%s': %s", cfg->filename, strerror(errno)); } free(cfg->content[i]); } fclose(fd); free(cfg->content); return 0; }
static int _charset_convert(lml_charset_t *lc, const char *in, size_t inlen, char **out, size_t *outlen) { char *outp; size_t ret, olen, bkpolen; bkpolen = olen = inlen * lc->max_char_size; if ( olen + 1 < olen ) return -1; *out = outp = malloc(olen + 1); if ( ! outp ) return -1; ret = iconv(lc->conv, (char **) &in, &inlen, &outp, &olen); if ( ret == (size_t) -1 ) { free(*out); prelude_log(PRELUDE_LOG_ERR, "ICONV: failed converting string to UTF-8: %s.\n", strerror(errno)); return -1; } *outlen = (bkpolen - olen); *outp = '\0'; return 0; }
int _prelude_log_set_abort_level_from_string(const char *level) { size_t i; char *eptr; long lvalue; struct { const char *prefix; prelude_log_t level; } tbl[] = { { "CRIT", PRELUDE_LOG_CRIT }, { "ERR", PRELUDE_LOG_ERR }, { "WARN", PRELUDE_LOG_WARN }, { "INFO", PRELUDE_LOG_INFO }, { "DEBUG", PRELUDE_LOG_DEBUG } }; prelude_return_val_if_fail(level != NULL, prelude_error(PRELUDE_ERROR_ASSERTION)); for ( i = 0; i < sizeof(tbl) / sizeof(*tbl); i++ ) { if ( strncasecmp(tbl[i].prefix, level, strlen(tbl[i].prefix)) == 0 ) { _prelude_log_set_abort_level(tbl[i].level); return 0; } } lvalue = strtol(level, &eptr, 10); if ( eptr != (level + strlen(level)) || lvalue == LONG_MIN || lvalue == LONG_MAX ) { prelude_log(PRELUDE_LOG_WARN, "Invalid abort level specified: '%s'.\n", level); return -1; } _prelude_log_set_abort_level(lvalue); return 0; }
static void print_stats(const char *prefix, struct timeval *end) { double tdiv; tdiv = (end->tv_sec + (double) end->tv_usec / 1000000) - (start.tv_sec + (double) start.tv_usec / 1000000); prelude_log(PRELUDE_LOG_WARN, "%s%lu line processed in %.2f seconds (%.2f EPS), %lu alert emited.\n", prefix, config.line_processed, tdiv, config.line_processed / tdiv, config.alert_count); }
static int _charset_open(lml_charset_t **lc, const char *from) { *lc = calloc(1, sizeof(**lc)); if ( ! *lc ) { prelude_log(PRELUDE_LOG_ERR, "ICONV: memory exhausted.\n"); return -1; } (*lc)->conv = iconv_open("UTF-8", from); if ( (*lc)->conv == (iconv_t) -1 ) { prelude_log(PRELUDE_LOG_ERR, "ICONV: couldn't open %s -> UTF-8 converter : %s.\n", from, strerror(errno)); free(*lc); return -1; } (*lc)->max_char_size = 4; /* Warning: this is UTF-8 specific */ return 0; }
static int accept_connection(server_generic_t *server, server_generic_client_t *cdata) { socklen_t addrlen; int ret, sock, on = 1; addrlen = sizeof(cdata->sa); sock = accept(server->sock, (struct sockaddr *) &cdata->sa, &addrlen); if ( sock < 0 ) { prelude_log(PRELUDE_LOG_ERR, "accept error: %s.\n", strerror(errno)); return -1; } ret = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(int)); if ( ret < 0 ) prelude_log(PRELUDE_LOG_ERR, "could not set SO_KEEPALIVE socket option: %s.\n", strerror(errno)); return sock; }
static int _charset_detect(const char *in, size_t len, const char **charset, int *confidence) { UCharsetDetector *csd; const UCharsetMatch *ucm; UErrorCode status = U_ZERO_ERROR; csd = ucsdet_open(&status); if ( U_FAILURE(status) ) { prelude_log(PRELUDE_LOG_ERR, "ICU: error opening character set detector: %s.\n", u_errorName(status)); return -1; } ucsdet_setText(csd, in, len, &status); if( U_FAILURE(status) ) { prelude_log(PRELUDE_LOG_ERR, "ICU: error setting text for character set detection: %s.\n", u_errorName(status)); goto error; } ucm = ucsdet_detect(csd, &status); if( U_FAILURE(status) ) { prelude_log(PRELUDE_LOG_ERR, "ICU: character set detection failed: %s.\n", u_errorName(status)); goto error; } *confidence = ucsdet_getConfidence(ucm, &status); if ( U_FAILURE(status) ) { prelude_log(PRELUDE_LOG_ERR, "ICU: error retrieving character set confidence: %s.\n", u_errorName(status)); goto error; } *charset = ucsdet_getName(ucm, &status); if ( U_FAILURE(status) ) { prelude_log(PRELUDE_LOG_ERR, "ICU: error retrieving character set name: %s.\n", u_errorName(status)); goto error; } return 0; error: ucsdet_close(csd); return -1; }
void server_generic_log_client(server_generic_client_t *cnx, prelude_log_t priority, const char *fmt, ...) { va_list ap; int ret = 0; prelude_string_t *out; char addr[128] = { 0 }; prelude_string_new(&out); if ( ((struct sockaddr *) &cnx->sa)->sa_family == AF_UNIX ) snprintf(addr, sizeof(addr), "unix"); else { void *in_addr; const char *str; unsigned int port; #ifdef HAVE_IPV6 port = ntohs(cnx->sa.sin6_port); #else port = ntohs(cnx->sa.sin_port); #endif in_addr = prelude_sockaddr_get_inaddr((struct sockaddr *) &cnx->sa); if ( ! in_addr ) goto out; str = inet_ntop(((struct sockaddr *)&cnx->sa)->sa_family, in_addr, addr, sizeof(addr)); if ( str ) snprintf(addr + strlen(addr), sizeof(addr) - strlen(addr), ":%u", port); } if ( cnx->ident && cnx->permission ) { ret = prelude_string_sprintf(out, " 0x%" PRELUDE_PRIx64, cnx->ident); if ( ret < 0 ) goto out; ret = prelude_connection_permission_to_string(cnx->permission, out); } ret = prelude_string_sprintf(out, "]: "); if ( ret < 0 ) goto out; va_start(ap, fmt); ret = prelude_string_vprintf(out, fmt, ap); va_end(ap); prelude_log(priority, "[%s%s", addr, prelude_string_get_string(out)); out: prelude_string_destroy(out); }
static UConverter *icu_initialize_converter(const char *charset) { UConverter *conv; UErrorCode status = U_ZERO_ERROR; conv = ucnv_open(charset, &status); if ( U_FAILURE(status) ) { prelude_log(PRELUDE_LOG_ERR, "ICU: couldn't open %s converter : %s.\n", charset, u_errorName(status)); return NULL; } return conv; }
static void handle_sighup(void) { int ret; /* * Here we go ! */ ret = execvp(global_argv[0], global_argv); if ( ret < 0 ) { prelude_log(PRELUDE_LOG_ERR, "error restarting '%s': %s\n", global_argv[0], prelude_strerror(ret)); return; } }
static pcre_rule_container_t *create_rule_container(pcre_rule_t *rule) { pcre_rule_container_t *rc; rc = calloc(1, sizeof(*rc)); if ( ! rc ) { prelude_log(PRELUDE_LOG_ERR, "memory exhausted.\n"); return NULL; } rc->rule = rule; rule->refcount++; return rc; }
static int sg_bind_common(server_generic_t *server, unsigned int port) { char out[128]; void *in_addr; #if ! ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) fcntl(server->sock, F_SETFD, fcntl(server->sock, F_GETFD) | FD_CLOEXEC); if ( server->sa->sa_family == AF_UNIX ) prelude_log(PRELUDE_LOG_INFO, "server started (listening on %s).\n", ((struct sockaddr_un *) server->sa)->sun_path); else { #endif in_addr = prelude_sockaddr_get_inaddr(server->sa); assert(in_addr); inet_ntop(server->sa->sa_family, in_addr, out, sizeof(out)); prelude_log(PRELUDE_LOG_INFO, "server started (listening on %s port %u).\n", out, port); #if ! ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) } #endif return 0; }
static int _charset_open(lml_charset_t **lc, const char *from) { *lc = calloc(1, sizeof(**lc)); if ( ! *lc ) { prelude_log(PRELUDE_LOG_ERR, "ICU: memory exhausted.\n"); return -1; } (*lc)->from = icu_initialize_converter(from); if ( ! (*lc)->from ) return lml_charset_close(*lc); (*lc)->to = icu_initialize_converter("UTF-8"); if ( ! (*lc)->to ) return lml_charset_close(*lc); (*lc)->max_char_size = ucnv_getMaxCharSize((*lc)->to); return 0; }
server_generic_t *server_generic_new(size_t clientlen, server_generic_accept_func_t *acceptf, server_generic_read_func_t *readf, server_generic_write_func_t *writef, server_generic_close_func_t *closef) { server_generic_t *server; server = malloc(sizeof(*server)); if ( ! server ) { prelude_log(PRELUDE_LOG_ERR, "memory exhausted.\n"); return NULL; } server->sa = NULL; server->read = readf; server->write = writef; server->accept = acceptf; server->close = closef; server->clientlen = clientlen; return server; }
int main(int argc, char **argv) { int ret; ev_timer evt; struct timeval end; struct sigaction action; /* * Initialize libev. */ ev_default_loop(EVFLAG_AUTO); /* * make sure we ignore sighup until acceptable. */ #if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) action.sa_flags = 0; action.sa_handler = SIG_IGN; sigemptyset(&action.sa_mask); sigaction(SIGHUP, &action, NULL); #endif memset(&start, 0, sizeof(start)); memset(&end, 0, sizeof(end)); prelude_init(&argc, argv); global_argv = argv; PRELUDE_PLUGIN_SET_PRELOADED_SYMBOLS(); ret = prelude_option_new_root(&lml_root_optlist); if ( ret < 0 ) return ret; ret = log_plugins_init(LOG_PLUGIN_DIR, lml_root_optlist); if (ret < 0) return ret; prelude_log_debug(1, "Initialized %d logs plugins.\n", ret); ret = lml_options_init(lml_root_optlist, argc, argv); if ( ret < 0 ) exit(1); /* * setup signal handling */ action.sa_flags = 0; sigemptyset(&action.sa_mask); action.sa_handler = sig_handler; #ifdef SA_INTERRUPT action.sa_flags |= SA_INTERRUPT; #endif sigaction(SIGTERM, &action, NULL); sigaction(SIGINT, &action, NULL); sigaction(SIGABRT, &action, NULL); #if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) sigaction(SIGUSR1, &action, NULL); sigaction(SIGQUIT, &action, NULL); sigaction(SIGHUP, &action, NULL); #endif ret = file_server_start_monitoring(); if ( ret < 0 && ! config.udp_nserver ) { prelude_log(PRELUDE_LOG_WARN, "No file or UDP server available for monitoring: terminating.\n"); return -1; } if ( config.daemon_mode ) { prelude_daemonize(config.pidfile); if ( config.pidfile ) free(config.pidfile); ev_default_fork(); } ev_timer_init(&evt, libev_timer_cb, 1, 1); ev_timer_start(&evt); /* * Whether we are using batch-mode or file notification, we need * to process the currently un-processed entry. */ gettimeofday(&start, NULL); do { ret = file_server_read_once(); prelude_timer_wake_up(); } while ( ret > 0 ); /* * if either FAM or UDP server is enabled, we use polling to know * if there are data available for reading. if batch_mode is set, * then we revert to reading every data at once. */ if ( ! config.batch_mode ) wait_for_event(); else { gettimeofday(&end, NULL); /* * only call prelude_client_destroy in case we are running in batch * mode, causing an heartbeat to be sent to notice of a normal exit. */ if ( ! config.dry_run ) prelude_client_destroy(config.lml_client, PRELUDE_CLIENT_EXIT_STATUS_SUCCESS); print_stats("", &end); } prelude_deinit(); return 0; }
static int read_option_list(prelude_msg_t *msg, prelude_option_t *opt, uint64_t *source_id) { int ret; void *buf; uint8_t tag; const char *tmp = NULL; uint32_t dlen, tmpint = 0; prelude_option_t *newopt; if ( ! opt ) return -1; while ( (ret = prelude_msg_get(msg, &tag, &dlen, &buf)) == 0 ) { switch (tag) { case PRELUDE_MSG_OPTION_START: ret = prelude_option_new(opt, &newopt); if ( ret < 0 ) break; read_option_list(msg, newopt, source_id); break; case PRELUDE_MSG_OPTION_END: return 0; case PRELUDE_MSG_OPTION_VALUE: ret = prelude_extract_characters_safe(&tmp, buf, dlen); if ( ret < 0 ) return ret; prelude_option_set_value(opt, tmp); break; case PRELUDE_MSG_OPTION_NAME: ret = prelude_extract_characters_safe(&tmp, buf, dlen); if ( ret < 0 ) return ret; prelude_option_set_longopt(opt, tmp); break; case PRELUDE_MSG_OPTION_DESC: ret = prelude_extract_characters_safe(&tmp, buf, dlen); if ( ret < 0 ) return ret; prelude_option_set_description(opt, tmp); break; case PRELUDE_MSG_OPTION_HELP: ret = prelude_extract_characters_safe(&tmp, buf, dlen); if ( ret < 0 ) return ret; prelude_option_set_help(opt, tmp); break; case PRELUDE_MSG_OPTION_INPUT_VALIDATION: ret = prelude_extract_characters_safe(&tmp, buf, dlen); if ( ret < 0 ) return ret; prelude_option_set_input_validation_regex(opt, tmp); break; case PRELUDE_MSG_OPTION_HAS_ARG: ret = prelude_extract_uint32_safe(&tmpint, buf, dlen); if ( ret < 0 ) return ret; prelude_option_set_has_arg(opt, tmpint); break; case PRELUDE_MSG_OPTION_TYPE: ret = prelude_extract_uint32_safe(&tmpint, buf, dlen); if ( ret < 0 ) return ret; prelude_option_set_type(opt, tmpint); break; case PRELUDE_MSG_OPTION_INPUT_TYPE: ret = prelude_extract_uint32_safe(&tmpint, buf, dlen); if ( ret < 0 ) return ret; prelude_option_set_input_type(opt, tmpint); break; default: /* * for compatibility purpose, don't return an error on unknow tag. */ prelude_log(PRELUDE_LOG_WARN, "unknown option tag %d.\n", tag); } } return 0; }
static void tls_log_func(int level, const char *data) { prelude_log(PRELUDE_LOG_INFO, "%s", data); }
int prelude_option_recv_reply(prelude_msg_t *msg, uint64_t *source_id, uint32_t *request_id, void **value) { void *buf; uint8_t tag; uint32_t dlen; int ret, type = -1; *value = NULL; while ( (ret = prelude_msg_get(msg, &tag, &dlen, &buf)) == 0 ) { switch (tag) { case PRELUDE_MSG_OPTION_HOP: break; case PRELUDE_MSG_OPTION_REQUEST_ID: type = PRELUDE_OPTION_REPLY_TYPE_SET; ret = prelude_extract_uint32_safe(request_id, buf, dlen); if ( ret < 0 ) return ret; break; case PRELUDE_MSG_OPTION_VALUE: type = PRELUDE_OPTION_REPLY_TYPE_GET; ret = prelude_extract_characters_safe((const char **) value, buf, dlen); if ( ret < 0 ) return ret; break; case PRELUDE_MSG_OPTION_ERROR: type = PRELUDE_OPTION_REPLY_TYPE_ERROR; if ( ! dlen ) { *value = "No error message"; break; } ret = prelude_extract_characters_safe((const char **) value, buf, dlen); if ( ret < 0 ) return ret; break; case PRELUDE_MSG_OPTION_TARGET_ID: if ( dlen % sizeof(uint64_t) != 0 || dlen < (2 * sizeof(uint64_t)) ) return -1; *source_id = prelude_extract_uint64((unsigned char *) buf + (dlen - sizeof(uint64_t))); break; case PRELUDE_MSG_OPTION_LIST: type = PRELUDE_OPTION_REPLY_TYPE_LIST; ret = prelude_option_new(NULL, (prelude_option_t **) value); if ( ret < 0 ) return ret; ret = read_option_list(msg, *value, NULL); if ( ret < 0 ) return ret; break; default: prelude_log(PRELUDE_LOG_WARN, "unknown option tag %d.\n", tag); } } return type; }