/* ** Modular Logfile Analyzer ** Copyright 2000 Jan Kneschke ** ** Homepage: http://www.modlogan.org ** 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 2 of the License, or (at your option) any later version, and provided that the above copyright and permission notice is included with all distributed copies of this or derived software. 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA ** ** $Id: parse.c,v 1.11 2003/09/05 06:42:43 miham Exp $ */ #include #include #include #include #include #include #include "mlocale.h" #include "mplugins.h" #include "mrecord.h" #include "mdatatypes.h" #include "misc.h" #include "plugin_config.h" #define DEBUG_PCRE const char *short_month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL}; int parse_timestamp(mconfig *ext_conf, const char *str, mlogrec *record) { #define N 20 + 1 int ovector[3 * N], n, i; char buf[10]; struct tm tm; config_input *conf = ext_conf->plugin_conf; if ((n = pcre_exec(conf->match_timestamp, NULL, str, strlen(str), 0, 0, ovector, 3 * N)) < 0) { if (n == PCRE_ERROR_NOMATCH) { M_DEBUG1(ext_conf->debug_level, M_DEBUG_SECTION_PARSING, M_DEBUG_LEVEL_ERRORS, "string doesn't match: %s\n", str); return M_RECORD_CORRUPT; } else { M_DEBUG1(ext_conf->debug_level, M_DEBUG_SECTION_PARSING, M_DEBUG_LEVEL_ERRORS, "execution error while matching: %d\n", n); return M_RECORD_HARD_ERROR; } } memset(&tm, 0, sizeof(struct tm)); /* everything has matched, take the different pieces and be happy :) */ pcre_copy_substring(str, ovector, n, 1, buf, sizeof(buf)); for (i = 0; short_month[i];i++) { if (!strcmp(buf, short_month[i])) { tm.tm_mon = i; } } pcre_copy_substring(str, ovector, n, 2, buf, sizeof(buf)); tm.tm_mday = strtol(buf, NULL, 10); pcre_copy_substring(str, ovector, n, 3, buf, sizeof(buf)); tm.tm_hour = strtol(buf, NULL, 10); pcre_copy_substring(str, ovector, n, 4, buf, sizeof(buf)); tm.tm_min = strtol(buf, NULL, 10); pcre_copy_substring(str, ovector, n, 5, buf, sizeof(buf)); tm.tm_sec = strtol(buf, NULL, 10); /* FIXME: 2001 is hardcoded */ tm.tm_year = 2003 - 1900; record->timestamp = mktime (&tm); return M_RECORD_NO_ERROR; #undef N } typedef struct { int type; pcre *match; } Matches; #if 0 /* to be added * * collected queue-ids ad removed them if all reciepients got their mails */ char **queue_ids = NULL; int queue_ids_size = 0; int queue_ids_used = 0; int insert_queue_id() { } #endif int parse_record_pcre(mconfig *ext_conf, mlogrec *record, buffer *b) { #define N 20 + 1 const char **list; int ovector[3 * N], n; int i, match; enum {M_SENDMAIL_FROM, M_SENDMAIL_TO, M_SENDMAIL_WARNING, M_SENDMAIL_NOQUEUE}; config_input *conf = ext_conf->plugin_conf; const Matches matches [] = { { M_SENDMAIL_FROM, conf->match_sendmail_from }, { M_SENDMAIL_TO, conf->match_sendmail_to }, { M_SENDMAIL_WARNING, conf->match_sendmail_warning }, { M_SENDMAIL_NOQUEUE, conf->match_sendmail_noqueue }, { 0, NULL } }; /* try to match the syslog prefix */ if ((n = pcre_exec(conf->match_syslog, NULL, b->ptr, b->used - 1, 0, 0, ovector, 3 * N)) < 0) { if (n == PCRE_ERROR_NOMATCH) { #if 1 fprintf(stderr, "%s.%d: syslog prefix doesn't match: %s\n", __FILE__, __LINE__, b->ptr); #endif return M_RECORD_IGNORED; } else { fprintf(stderr, "%s.%d: execution error while matching: %d\n", __FILE__, __LINE__, n); return M_RECORD_HARD_ERROR; } } /* ok, it's a syslog - the rest should be sendmail specific */ if (n) { char queue_id[256]; int ret; i = 0; match = -1; /* get timestamp and queue id */ /* temporary misuse 'queue_id' */ pcre_copy_substring(b->ptr, ovector, n, 1, queue_id, sizeof(queue_id)); switch(ret = parse_timestamp(ext_conf, queue_id, record)) { case M_RECORD_NO_ERROR: break; case M_RECORD_HARD_ERROR: fprintf(stderr, "%s.%d: parse_timestamp died on %s\n", __FILE__, __LINE__, b->ptr); return M_RECORD_HARD_ERROR; case M_RECORD_IGNORED: return M_RECORD_IGNORED; case M_RECORD_CORRUPT: return M_RECORD_CORRUPT; default: fprintf(stderr, "%s.%d: parse_timestamp return a unknown ret-value on %d\n", __FILE__, __LINE__, ret); return M_RECORD_HARD_ERROR; } pcre_copy_substring(b->ptr, ovector, n, 2, queue_id, sizeof(queue_id)); while ( matches[i].match != NULL ) { /* find the corresponding match */ if ((n = pcre_exec(matches[i].match, NULL, b->ptr, b->used - 1, 0, 0, ovector, 3 * N)) < 0) { if (n == PCRE_ERROR_NOMATCH) { i++; continue; } else { fprintf(stderr, "%s.%d: execution error while matching: %d\n", __FILE__, __LINE__, n); return M_RECORD_HARD_ERROR; } } else { match = matches[i].type; break; } } if (n > 1 && match != -1) { pcre_get_substring_list(b->ptr, ovector, n, &list); switch (match) { case M_SENDMAIL_FROM: { #if 0 printf( "MATCH_FROM\n" ); for (i = 1; i < n; i++) { printf("%d: %s; ", i, list[i]); } printf("\n"); #endif mlogrec_mail * recmail = mrecord_init_mail(); record->ext_type = M_RECORD_TYPE_MAIL; record->ext = recmail; /* open queue with queue id */ /* set nrptcs */ recmail->sender = malloc(strlen((char *)list[1]) + 1); strcpy(recmail->sender, (char *)list[1]); recmail->bytes_in = strtol((char *)list[2], NULL, 10); } break; case M_SENDMAIL_TO: /* check if all rcpt are successfull */ /* if yes, remove queue-id */ #if 0 printf( "MATCH_TO\n" ); for (i = 1; i < n; i++) { printf("%d: %s; ", i, list[i]); } printf("\n"); #endif break; case M_SENDMAIL_WARNING: case M_SENDMAIL_NOQUEUE: #if 0 printf( (match == M_SENDMAIL_WARNING) ? "MATCH_WARNING\n" : "MATCH_NOQUEUE\n" ); printf( "Queue id = '%s'\n", queue_id ); for (i = 1; i < n; i++) { printf("%d: %s; ", i, list[i]); } printf("\n"); #endif break; default: #if 0 printf( "FAILED PATTERN!\n" ); for (i = 1; i < n; i++) { printf("%d: %s; ", i, list[i]); } printf("\n"); #endif break; } free(list); return record->ext ? M_RECORD_NO_ERROR : M_RECORD_IGNORED; } else { M_DEBUG1(ext_conf->debug_level, M_DEBUG_SECTION_PARSING, M_DEBUG_LEVEL_WARNINGS, "corrupt -> %s\n", b->ptr ); return M_RECORD_CORRUPT; } } else { M_DEBUG0(ext_conf->debug_level, M_DEBUG_SECTION_PARSING, M_DEBUG_LEVEL_WARNINGS, "corrupt - n = 0\n" ); return M_RECORD_CORRUPT; } return M_RECORD_IGNORED; #undef N } int mplugins_input_sendmail_get_next_record(mconfig *ext_conf, mlogrec *record) { int ret = 0; config_input *conf = ext_conf->plugin_conf; if (record == NULL) return M_RECORD_HARD_ERROR; /* fill the line buffer */ if (NULL == mgets(&(conf->inputfile), conf->buf)) return M_RECORD_EOF; ret = parse_record_pcre (ext_conf, record, conf->buf); if (ret == M_RECORD_CORRUPT) { M_DEBUG1(ext_conf->debug_level, M_DEBUG_SECTION_PARSING, M_DEBUG_LEVEL_WARNINGS, "affected Record: %s\n", conf->buf->ptr ); } return ret; }