/* vi: set et ts=4: */ /* Copyright (C) 2007-2011 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * 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 * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Mike Pomraning * * File-like output for logging: regular files and sockets. */ #include #include #include "suricata-common.h" /* errno.h, string.h, etc. */ #include "tm-modules.h" /* LogFileCtx */ #include "conf.h" /* ConfNode, etc. */ #include "output.h" /* DEFAULT_LOG_* */ /** \brief connect to the indicated local stream socket, logging any errors * \param path filesystem path to connect to * \retval FILE* on success (fdopen'd wrapper of underlying socket) * \retval NULL on error */ static FILE * SCLogOpenUnixSocketFp(const char *path, int sock_type) { struct sockaddr_un sun = {0}; int s = -1; FILE * ret = NULL; s = socket(PF_UNIX, sock_type, 0); if (s < 0) goto err; sun.sun_family = AF_UNIX; strncpy(sun.sun_path, path, sizeof(sun.sun_path) - 1); if (connect(s, (const struct sockaddr *)&sun, sizeof(sun)) < 0) goto err; ret = fdopen(s, "w"); if (ret == NULL) goto err; return ret; err: SCLogError(SC_ERR_SOCKET, "Error connecting to socket \"%s\": %s", path, strerror(errno)); if (s >= 0) close(s); return NULL; } /** \brief open the indicated file, logging any errors * \param path filesystem path to open * \param append_setting open file with O_APPEND: "yes" or "no" * \retval FILE* on success * \retval NULL on error */ static FILE * SCLogOpenFileFp(const char *path, const char *append_setting) { FILE *ret = NULL; if (strcasecmp(append_setting, "yes") == 0) { ret = fopen(path, "a"); } else { ret = fopen(path, "w"); } if (ret == NULL) SCLogError(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", path, strerror(errno)); return ret; } /** \brief open a generic output "log file", which may be a regular file or a socket * \param conf ConfNode structure for the output section in question * \param log_ctx Log file context allocated by caller * \param default_filename Default name of file to open, if not specified in ConfNode * \retval 0 on success * \retval -1 on error */ int SCConfLogOpenGeneric(ConfNode *conf, LogFileCtx *log_ctx, const char *default_filename) { char log_path[PATH_MAX]; char *log_dir; const char *filename, *filetype; // Arg check if (conf == NULL || log_ctx == NULL || default_filename == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "SCConfLogOpenGeneric(conf %p, ctx %p, default %p) " "missing an argument", conf, log_ctx, default_filename); return -1; } if (log_ctx->fp != NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "SCConfLogOpenGeneric: previously initialized Log CTX " "encountered"); return -1; } // Resolve the given config filename = ConfNodeLookupChildValue(conf, "filename"); if (filename == NULL) filename = default_filename; if (ConfGet("default-log-dir", &log_dir) != 1) log_dir = DEFAULT_LOG_DIR; snprintf(log_path, PATH_MAX, "%s/%s", log_dir, filename); filetype = ConfNodeLookupChildValue(conf, "filetype"); if (filetype == NULL) filetype = DEFAULT_LOG_FILETYPE; // Now, what have we been asked to open? if (strcasecmp(filetype, "unix_stream") == 0) { log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_STREAM); } else if (strcasecmp(filetype, "unix_dgram") == 0) { log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_DGRAM); } else if (strcasecmp(filetype, DEFAULT_LOG_FILETYPE) == 0) { const char *append; append = ConfNodeLookupChildValue(conf, "append"); if (append == NULL) append = DEFAULT_LOG_MODE_APPEND; log_ctx->fp = SCLogOpenFileFp(log_path, append); } else { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "%s.type. Expected \"regular\" (default), \"unix_stream\" " "or \"unix_dgram\"", conf->name); } if (log_ctx->fp == NULL) return -1; // Error already logged by Open...Fp routine SCLogInfo("%s output device (%s) initialized: %s", conf->name, filetype, filename); return 0; }