/*
* sma -- Sendmail log analyser
*
* Copyright (c) 2000 - 2003 Jarkko Turkulainen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY JARKKO TURKULAINEN ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL JARKKO TURKULAINEN BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Date: 2002/12/06 12:48:51 $
*/
/* Copyright for routines in scan_time() */
/*
* Copyright (c) 1985, 1987, 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "sma.h"
int isdigit(int);
/*
* Take month as an ascii string and return integer
*/
int
conv_mon(const char *mon) {
int k;
const char *montab[] = {
"Jan", "Feb", "Mar", "Apr", "May",
"Jun", "Jul", "Aug", "Sep", "Oct",
"Nov", "Dec"
};
for (k = 0; k < 12; k++) {
if (!strcmp(mon, montab[k]))
break;
}
return k;
}
/*
* Take month, day, hour, minute and second as integers
* and return time_t
*/
time_t
conv_time(int mon, int day, int hh, int min, int sec) {
/*
* Assume that the year is current year...
* This is bug.
*/
/* sanity check: */
if (mon < 0 || mon >= 12)
return (time_t)NULL;
/* fill the structure: */
tp.tm_sec=sec;
tp.tm_min=min;
tp.tm_hour=hh;
tp.tm_mday=day;
tp.tm_mon=mon;
tp.tm_year=curr->tm_year;
tp.tm_isdst=-1;
return mktime(&tp);
}
void
scan_time(time_t *utime, char *p) {
#define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
struct tm *lt;
char *t, *dot;
int bigyear;
int yearset = 0;
for (t = p, dot = NULL; *t; ++t) {
if (isdigit(*t))
continue;
if (*t == '.' && dot == NULL) {
dot = t;
continue;
}
usage();
}
tval = time((time_t *)NULL);
lt = localtime(&tval);
lt->tm_isdst = -1; /* correct for DST */
if (dot != NULL) { /* .SS */
*dot++ = '\0';
if (strlen(dot) != 2)
usage();
lt->tm_sec = ATOI2(dot);
if (lt->tm_sec > 61)
usage();
} else
lt->tm_sec = 0;
switch (strlen(p)) {
case 12: /* cc */
bigyear = ATOI2(p);
lt->tm_year = bigyear * 100 - 1900;
yearset = 1;
/* FALLTHROUGH */
case 10: /* yy */
if (yearset) {
lt->tm_year += ATOI2(p);
} else {
lt->tm_year = ATOI2(p);
if (lt->tm_year < 69) /* hack for 2000 ;-} */
lt->tm_year += (2000 - 1900);
else
lt->tm_year += (1900 - 1900);
}
/* FALLTHROUGH */
case 8: /* mm */
lt->tm_mon = ATOI2(p);
if ((lt->tm_mon > 12) || !lt->tm_mon)
usage();
--lt->tm_mon; /* time struct is 0 - 11 */
/* FALLTHROUGH */
case 6: /* dd */
lt->tm_mday = ATOI2(p);
if ((lt->tm_mday > 31) || !lt->tm_mday)
usage();
/* FALLTHROUGH */
case 4: /* HH */
lt->tm_hour = ATOI2(p);
if (lt->tm_hour > 23)
usage();
/* FALLTHROUGH */
case 2: /* MM */
lt->tm_min = ATOI2(p);
if (lt->tm_min > 59)
usage();
break;
default:
usage();
}
*utime = mktime(lt);
}
/*
* Prepare a space for sorted address stuctures and do the sorting
*/
void
sort(struct host *hptr) {
int i, j, k;
struct envpair *eptr;
struct in *iptr;
struct out *optr;
struct relpair *rptr;
struct rin *riptr;
struct rout *roptr;
struct status *statptr;
struct rule *ruleptr;
struct rrelay *rrptr;
/* space for sorted structures: */
if (!(hptr->setab = malloc(hptr->edif * sizeof(struct envpair *))))
error_memory();
if (!(hptr->sitab = malloc(hptr->idif * sizeof(struct sin *))))
error_memory();
if (!(hptr->sotab = malloc(hptr->odif * sizeof(struct sout *))))
error_memory();
if (!(hptr->srtab = malloc(hptr->rrdif * sizeof(struct relpair *))))
error_memory();
if (!(hptr->rsitab = malloc(hptr->ridif * sizeof(struct rin *))))
error_memory();
if (!(hptr->rsotab = malloc(hptr->rodif * sizeof(struct rout *))))
error_memory();
if (!(hptr->ssttab = malloc(hptr->sdif * sizeof(struct status *))))
error_memory();
if (!(hptr->sruletab = malloc(hptr->rdif * sizeof(struct rule *))))
error_memory();
/* envelope pairs: */
for (i = 0, k = 0; k < asize; k++)
for (eptr = hptr->etab[k]; eptr; eptr = eptr->next)
/* copy pointers: */
hptr->setab[i++] = eptr;
/* relay pairs: */
for (i = 0, k = 0; k < rsize; k++)
for (rptr = hptr->rtab[k]; rptr; rptr = rptr->next)
/* copy pointers: */
hptr->srtab[i++] = rptr;
/* input: */
for (i = 0, k = 0; k < asize; k++)
for (iptr = hptr->itab[k]; iptr; iptr = iptr->next)
/* copy pointers: */
hptr->sitab[i++] = iptr;
for (i = 0, k = 0; k < rsize; k++)
for (riptr = hptr->ritab[k]; riptr; riptr = riptr->next)
/* copy pointers: */
hptr->rsitab[i++] = riptr;
/* output: */
for (i = 0, k = 0; k < asize; k++)
for (optr = hptr->otab[k]; optr; optr = optr->next)
/* copy pointers: */
hptr->sotab[i++] = optr;
for (i = 0, k = 0; k < rsize; k++)
for (roptr = hptr->rotab[k];roptr; roptr = roptr->next)
/* copy pointers: */
hptr->rsotab[i++] = roptr;
/* status and ruleset: */
for (i = 0, k = 0; k < rsize; k++)
for (statptr = hptr->sttab[k]; statptr; statptr = statptr->next)
/* copy pointers: */
hptr->ssttab[i++] = statptr;
for (i = 0, k = 0; k < rsize; k++)
for (ruleptr = hptr->ruletab[k]; ruleptr; ruleptr = ruleptr->next) {
/* copy pointers: */
hptr->sruletab[i++] = ruleptr;
/* alloc space for sorted relays: */
if (!(ruleptr->srrelaytab =
malloc(ruleptr->reldif * sizeof(struct rrelay *))))
error_memory();
for (j = 0, rrptr = ruleptr->rrelaytab; rrptr;
rrptr = rrptr->next)
ruleptr->srrelaytab[j++] = rrptr;
/* sort */
qsort(ruleptr->srrelaytab, ruleptr->reldif,
sizeof(struct rrelay *), comp_rrel);
}
/* sort */
qsort(hptr->setab, hptr->edif, sizeof(struct envpair *), comp_env);
qsort(hptr->sitab, hptr->idif, sizeof(struct in *), comp_in);
qsort(hptr->sotab, hptr->odif, sizeof(struct out *), comp_out);
qsort(hptr->srtab, hptr->rrdif, sizeof(struct relpair *), comp_rel);
qsort(hptr->rsitab, hptr->ridif, sizeof(struct rin *), comp_rin);
qsort(hptr->rsotab, hptr->rodif, sizeof(struct rout *), comp_rout);
qsort(hptr->ssttab, hptr->sdif, sizeof(struct status *), comp_s);
qsort(hptr->sruletab, hptr->rdif, sizeof(struct rule *), comp_r);
}
/*
* Comparing functions, called from sort()
*/
int
comp_env(const void *p1, const void *p2) {
const struct envpair * sp1 = *(const struct envpair * const *)p1;
const struct envpair * sp2 = *(const struct envpair * const *)p2;
if (sflag) {
if (sp1->size < sp2->size)
return (1);
if (sp1->size > sp2->size)
return (-1);
} else {
if (sp1->num < sp2->num)
return (1);
if (sp1->num > sp2->num)
return (-1);
}
return (0);
}
int
comp_rel(const void *p1, const void *p2) {
const struct relpair * sp1 = *(const struct relpair * const *)p1;
const struct relpair * sp2 = *(const struct relpair * const *)p2;
if (sflag) {
if (sp1->size < sp2->size)
return (1);
if (sp1->size > sp2->size)
return (-1);
} else {
if (sp1->num < sp2->num)
return (1);
if (sp1->num > sp2->num)
return (-1);
}
return (0);
}
int
comp_in(const void *p1, const void *p2) {
const struct in * sp1 = *(const struct in * const *)p1;
const struct in * sp2 = *(const struct in * const *)p2;
if (sflag) {
if (sp1->size < sp2->size)
return (1);
if (sp1->size > sp2->size)
return (-1);
} else {
if (sp1->num < sp2->num)
return (1);
if (sp1->num > sp2->num)
return (-1);
}
return (0);
}
int
comp_rin(const void *p1, const void *p2) {
const struct rin * sp1 = *(const struct rin * const *)p1;
const struct rin * sp2 = *(const struct rin * const *)p2;
if (sflag) {
if (sp1->size < sp2->size)
return (1);
if (sp1->size > sp2->size)
return (-1);
} else {
if (sp1->num < sp2->num)
return (1);
if (sp1->num > sp2->num)
return (-1);
}
return (0);
}
int
comp_out(const void *p1, const void *p2) {
const struct out * sp1 = *(const struct out * const *)p1;
const struct out * sp2 = *(const struct out * const *)p2;
if (sflag) {
if (sp1->size < sp2->size)
return (1);
if (sp1->size > sp2->size)
return (-1);
} else {
if (sp1->num < sp2->num)
return (1);
if (sp1->num > sp2->num)
return (-1);
}
return (0);
}
int
comp_rout(const void *p1, const void *p2) {
const struct rout * sp1 = *(const struct rout * const *)p1;
const struct rout * sp2 = *(const struct rout * const *)p2;
if (sflag) {
if (sp1->size < sp2->size)
return (1);
if (sp1->size > sp2->size)
return (-1);
} else {
if (sp1->num < sp2->num)
return (1);
if (sp1->num > sp2->num)
return (-1);
}
return (0);
}
int
comp_s(const void *p1, const void *p2) {
const struct status * sp1 = *(const struct status * const *)p1;
const struct status * sp2 = *(const struct status * const *)p2;
if (sp1->num < sp2->num)
return (1);
if (sp1->num > sp2->num)
return (-1);
return (0);
}
int
comp_r(const void *p1, const void *p2) {
const struct rule * sp1 = *(const struct rule * const *)p1;
const struct rule * sp2 = *(const struct rule * const *)p2;
if (sp1->num < sp2->num)
return (1);
if (sp1->num > sp2->num)
return (-1);
return (0);
}
int
comp_rrel(const void *p1, const void *p2) {
const struct rrelay * sp1 = *(const struct rrelay * const *)p1;
const struct rrelay * sp2 = *(const struct rrelay * const *)p2;
if (sp1->num < sp2->num)
return (1);
if (sp1->num > sp2->num)
return (-1);
return (0);
}
/*
* Calculate the average daily/hour messages
*/
void
average(struct host *hptr, int *dd, float *ad, int *hh, float *ah) {
int fulld;
int fullh;
int weeks;
int hours;
int hfday, hfhour;
int i;
hfday = hptr->fday;
hfhour = hptr->fhour;
/* integer value of hours: */
fullh = (int)hptr->dtime/3600;
fullh++;
/* integer value of days: */
fulld = (int)hptr->dtime/(24*3600);
fulld++;
/*
* calculate full weeks:
*
* days left over from last full week are returned
* as int fulld:
*/
weeks = 0;
for (; fulld >= 7; fulld -= 7)
weeks++;
/* calculate daily averages: */
for (i = 0; i < 7; i++)
if (i == hfday && fulld > 0) {
ad[i] = (float)dd[i] / ((float)weeks + 1.0);
fulld--;
hfday++;
} else
if (weeks)
ad[i] = (float)dd[i] / (float)weeks;
else
ad[i] = (float)dd[i];
/* same calculations for hours: */
hours = 0;
for (; fullh >= 24; fullh -= 24)
hours++;
for (i = 0; i < 24; i++)
if (i == hfhour && fullh > 0) {
ah[i] = (float)hh[i] / ((float)hours + 1.0);
fullh--;
hfhour++;
} else
if (hours)
ah[i] = (float)hh[i] / (float)hours;
else
ah[i] = (float)hh[i];
}
/* Strip newline: */
char *
stripn(char *s) {
char *p;
for (p = s; *s != '\n'; s++)
;
*s = '\0';
return p;
}
void
error_memory() {
fprintf(stderr, "%s: memory allocation failure, errno: %d\n",
pname, errno);
exit(1);
}
void
copying() {
fprintf(stderr, "\nSMA version %s\n\n" , VERSION);
fprintf(stderr, "This program is Copyright (c) 2000 - 2003\n"
" Jarkko Turkulainen. All rights reserved.\n"
"Some parts are "
"Copyright (c) 1992, 1993, 1994\n"
" Henry Spencer. All rights reserved.\n"
"Some parts are "
"Copyright (c) 1985, 1987, 1988, 1993, 1994\n"
" The Regents of the University of California. "
"All rights reserved.\n\n");
exit(0);
}
void
usage() {
/* Use stdout - easier to "more" or "less" .. */
fprintf(stdout, "\nSMA version %s\n\n" , VERSION);
fprintf(stdout, "usage: %s [OPTIONS] [files...]\n"
"OPTIONS are\n"
" -A\t\tforce addresses to lower case to help with consistent counts\n"
" -a\t\tset the output format as ascii\n"
" -b <rgb>\tbackground color (RGB) of the HTML form\n"
" -c\t\tshow copyright information and exit\n"
" -C <string>\tset report header as <string>\n"
" -D <d1,d2>\tanalyse only log entries between dates d1 and d2\n"
" -d\t\tprint only the domain portion of email addresses\n"
" -f <file>\tuse configuration from <file> instead of default\n"
" -F\t\tdo not use default configuration file even if it exists\n"
" -h\t\tprint this text and exit\n"
" -H <name>\toverride the hostname with <name>\n"
" -i\t\tprint ASCII report as HTML comment (requires -w or -O html)\n"
" -L <string>\tprocess only lines with syslog tag <string>\n"
" -n\t\tdo not print the time distribution\n"
" -o <file>\twrite output to <file>\n"
" -O <format>\tset output format (ascii/html/clog)\n"
" -p\t\tprint current configuration to stdout\n"
" -s\t\tsort by tranfers\n"
" -q\t\tbe quiet (no error messages)\n"
" -v\t\tshow debugging information\n"
" -l <num>\tprint <num> top addresses\n"
" -r <num>\tprint <num> top relay addresses\n"
" -t <value>\tset the internal hash table size (normal/big/huge/a,r)\n"
" -w\t\tset the output format as html\n"
" files\tlog files\n\n", pname);
exit(0);
}
void
dump_config(FILE *handle) {
char *p = NULL;
char dates[128];
fprintf(handle, " BgColor %s\n", bchar);
fprintf(handle, " BounceAddress %s\n", bechar);
fprintf(handle, " CaseSensitive %s\n", csflag ? "no" : "yes");
if (cfchar)
fprintf(handle, " ClogFormat \"%s\"\n", cfchar);
fprintf(handle, " ClogSentOnly %s\n", clsflag ? "yes" : "no");
fprintf(handle, " Comment \"%s\"\n", Cchar);
fprintf(handle, " Debug %s\n", vflag ? "yes" : "no");
if (eetime) {
strftime(dates, 127, "%Y/%m/%d-%H:%M:%S", localtime(&eetime));
fprintf(handle, " EndTime %s\n", dates);
}
fprintf(handle, " EnvelopePairs %d\n", epnum);
fprintf(handle, " EnvelopeRecipientFilter %s\n", ref ? ref : "*");
fprintf(handle, " EnvelopeRecipients %d\n", lrnum);
fprintf(handle, " EnvelopeSenderFilter %s\n", sef ? sef : "*");
fprintf(handle, " EnvelopeSenders %d\n", lnum);
if (ftchar)
fprintf(handle, " FooterText \"%s\"\n", ftchar);
switch(Oflag) {
case FORMAT_ASCII:
if (!(p = strdup("ascii")))
error_memory();
break;
case FORMAT_HTML:
if (!(p = strdup("html")))
error_memory();
break;
case FORMAT_CLOG:
if (!(p = strdup("clog")))
error_memory();
break;
}
fprintf(handle, " Format %s\n", p);
free(p);
fprintf(handle, " HashTables %d,%d\n", asize, rsize);
if (htchar)
fprintf(handle, " HeaderText \"%s\"\n", htchar);
if (Hchar)
fprintf(handle, " HostName \"%s\"\n", Hchar);
fprintf(handle, " IncludeAscii %s\n", iflag ? "yes" : "no");
if (ochar)
fprintf(handle, " OutFile \"%s\"\n", ochar);
if (plchar)
fprintf(handle, " PictureLink \"%s\"\n", plchar);
if (ppchar)
fprintf(handle, " PictureParameters \"%s\"\n", ppchar);
if (pachar)
fprintf(handle, " PictureURL %s\n", pachar);
fprintf(handle, " PrintGeneralInfo %s\n", pgflag ? "yes" : "no");
fprintf(handle, " PrintRuleset %s\n", rsnum ? "yes" : "no");
fprintf(handle, " PrintStatus %s\n", stnum ? "yes" : "no");
fprintf(handle, " RelayPairs %d\n", rpnum);
fprintf(handle, " RelayRecipientFilter %s\n", rrf ? rrf : "*");
fprintf(handle, " RelayRecipients %d\n", rrnum);
fprintf(handle, " RelaySenderFilter %s\n", srf ? srf : "*");
fprintf(handle, " RelaySenders %d\n", rnum);
fprintf(handle, " RulesetRelays %d\n", rsrnum);
fprintf(handle, " ShowUsers %s\n", dflag ? "no" : "yes");
fprintf(handle, " Silent %s\n", qflag ? "yes" : "no");
fprintf(handle, " Sorting %s\n", sflag ? "transfer" : "number");
if (sstime) {
strftime(dates, 127, "%Y/%m/%d-%H:%M:%S", localtime(&sstime));
fprintf(handle, " StartTime %s\n", dates);
}
if (Lchar)
fprintf(handle, " SyslogTag %s\n", Lchar);
fprintf(handle, " TbColor %s\n", tbchar);
}
syntax highlighted by Code2HTML, v. 0.9.1