/* * This is an auditd plugin for sending auditd data * to clickhouse DB. * Copyright (C) 2020 Aleksei Nikiforov <darktemplar@basealt.ru> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ #include "logging.hpp" #include <time.h> #include <boost/scope_exit.hpp> std::mutex Logger::s_mutex; Logger::Logger() : m_initialized(false) { } Logger::~Logger() { dump_impl(); } Logger& Logger::instance() { static Logger s_instance; return s_instance; } void Logger::open(const char *filename) { std::lock_guard<std::mutex> lock(s_mutex); instance().open_impl(filename); } void Logger::initialize() { std::lock_guard<std::mutex> lock(s_mutex); instance().initialize_impl(); } void Logger::write(const char *format, ...) { std::lock_guard<std::mutex> lock(s_mutex); va_list args; va_start(args, format); instance().write_impl(format, args); va_end(args); } void Logger::dump() { std::lock_guard<std::mutex> lock(s_mutex); instance().dump_impl(); } void Logger::open_impl(const char *filename) { m_logfile_name = filename; initialize_impl(); } void Logger::initialize_impl() { m_initialized = true; } void Logger::write_impl(const char *format, va_list args) { FILE *outfile = NULL; std::string datestring = getdatestring(); if (!m_logfile_name.empty()) { outfile = fopen(m_logfile_name.c_str(), "at"); } if (outfile != NULL) { fprintf(outfile, "%s: ", datestring.c_str()); vfprintf(outfile, format, args); fprintf(outfile, "\n"); fclose(outfile); } else { // save logged data for later use char *data = NULL; BOOST_SCOPE_EXIT(&data) { if (data != NULL) { free(data); } } BOOST_SCOPE_EXIT_END; int result = vasprintf(&data, format, args); if ((result >= 0) && (data != NULL)) { m_lines.push_back(std::make_pair(datestring,data)); } if (m_initialized) { dump_impl(); } } } void Logger::dump_impl() { FILE *outfile = NULL; if (!m_logfile_name.empty()) { outfile = fopen(m_logfile_name.c_str(), "at"); } for (auto iter = m_lines.begin(); iter != m_lines.end(); ++iter) { fprintf((outfile != NULL) ? outfile : stderr, "%s: %s\n", iter->first.c_str(), iter->second.c_str()); } if (outfile != NULL) { fclose(outfile); } else { fflush(stderr); } m_lines.clear(); } std::string Logger::getdatestring() const { std::string result; time_t t = time(nullptr); struct tm tm_inst; auto tm_ptr = localtime_r(&t, &tm_inst); if (tm_ptr != nullptr) { char buffer[4096]; auto buffer_res = strftime(buffer, sizeof(buffer) - 1, "%c %Z", tm_ptr); if (buffer_res > 0) { buffer[buffer_res] = 0; result = buffer; } } return result; }