/*
* 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: 2003/04/03 12:42:33 $
*/
#include "sma.h"
/* hash function, stolen from O'Reilly book */
unsigned
hash(const char *s, int size) {
unsigned val;
val = 0;
while (*s != '\0') {
int tmp;
val = (val << 4) + (*s);
if ((tmp = (val & 0xf0000000U))) {
val = val ^ (tmp >> 24);
val = val ^ tmp;
}
s++;
}
return val % size;
}
/* initialize host struct: */
struct host *
init_host(const char *s) {
struct host *ptr;
for (ptr = first.next; ptr; ptr = ptr->next)
if (!(strcmp(s, ptr->name)))
return ptr;
hosts++;
/* space: */
if (!(ptr = malloc(sizeof(*ptr))))
error_memory();
if (!(ptr->name = strdup(s)))
error_memory();
/* inital values: */
if (!(ptr->etab = malloc(asize * sizeof(struct envpair *))))
error_memory();
memset(ptr->etab, 0, sizeof(struct envpair *) * asize);
if (!(ptr->itab = malloc(asize * sizeof(struct in *))))
error_memory();
memset(ptr->itab, 0, sizeof(struct in *) * asize);
if (!(ptr->otab = malloc(asize * sizeof(struct out *))))
error_memory();
memset(ptr->otab, 0, sizeof(struct out *) * asize);
if (!(ptr->rtab = malloc(rsize * sizeof(struct envpair *))))
error_memory();
memset(ptr->rtab, 0, sizeof(struct envpair *) * rsize);
if (!(ptr->ritab = malloc(rsize * sizeof(struct rin *))))
error_memory();
memset(ptr->ritab, 0, sizeof(struct rin *) * rsize);
if (!(ptr->rotab = malloc(rsize * sizeof(struct rout *))))
error_memory();
memset(ptr->rotab, 0, sizeof(struct rout *) * rsize);
if (!(ptr->sttab = malloc(rsize * sizeof(struct status *))))
error_memory();
memset(ptr->sttab, 0, sizeof(struct status *) * rsize);
if (!(ptr->ruletab = malloc(rsize * sizeof(struct rule *))))
error_memory();
memset(ptr->ruletab, 0, sizeof(struct rule *) * rsize);
ptr->msgidtab = NULL;
ptr->omsgidtab = NULL;
ptr->alias = 0;
ptr->hopc = 0;
ptr->lcerror = 0;
ptr->oserror = 0;
ptr->dstart = 0;
memset(ptr->ihh, 0, sizeof(int) * 24);
memset(ptr->fihh, 0, sizeof(float) * 24);
memset(ptr->idd, 0, sizeof(int) * 7);
memset(ptr->fidd, 0, sizeof(float) * 7);
memset(ptr->ohh, 0, sizeof(int) * 24);
memset(ptr->fohh, 0, sizeof(float) * 24);
memset(ptr->odd, 0, sizeof(int) * 7);
memset(ptr->fodd, 0, sizeof(float) * 7);
ptr->inum = 0;
ptr->onum = 0;
ptr->gonum = 0;
ptr->rinum = 0;
ptr->ronum = 0;
ptr->sent = 0;
ptr->queu = 0;
ptr->hunk = 0;
ptr->uunk = 0;
ptr->service = 0;
ptr->other = 0;
ptr->defe = 0;
ptr->rule = 0;
ptr->size = 0;
ptr->isize = 0;
ptr->osize = 0;
ptr->lsize = 0;
ptr->edif = 0;
ptr->idif = 0;
ptr->odif = 0;
ptr->rrdif = 0;
ptr->ridif = 0;
ptr->rodif = 0;
ptr->sdif = 0;
ptr->rdif = 0;
ptr->fhost = 0;
/* utilize next pointer: */
ptr->next = first.next;
first.next = ptr;
return ptr;
}
/* update input struct: */
void
update_in(struct host *hptr, const char *s, int ssize) {
unsigned hashval;
struct in *ptr;
for (ptr = hptr->itab[hash(s,asize)]; ptr; ptr = ptr->next)
if (!strcmp(s, ptr->name)) {
ptr->size += ssize;
ptr->num++;
return;
}
/* number of _different_ addresses: */
hptr->idif++;
/* space: */
if (!(ptr = malloc(sizeof(*ptr))))
error_memory();
if (!(ptr->name = strdup(s)))
error_memory();
/* initial values: */
ptr->num = 1;
ptr->size = ssize;
/* space for next one: */
hashval = hash(s,asize);
ptr->next = hptr->itab[hashval];
hptr->itab[hashval] = ptr;
}
/* remove input structure */
void
remove_in(struct host *hptr, const char *s, int size) {
unsigned hashval;
struct in *ptr, *prev;
if (vflag) fprintf(stderr, " removing %s... ", s);
hashval = hash(s,asize);
prev = NULL;
for (ptr = hptr->itab[hashval]; ptr; ptr = ptr->next) {
if (!strcmp(s, ptr->name)) {
ptr->num--;
ptr->size -= size;
if (ptr->num) {
if (vflag) fprintf(stderr, "OK\n");
return;
}
if (prev == NULL)
hptr->itab[hashval] = ptr->next;
else
prev->next = ptr->next;
free(ptr->name);
free(ptr);
if (vflag) fprintf(stderr, "OK\n");
hptr->idif--;
return;
}
prev = ptr;
}
if (vflag) fprintf(stderr, "not found\n");
}
/* update output struct: */
void
update_out(struct host *hptr, const char *s, int ssize) {
unsigned hashval;
struct out *ptr;
for (ptr = hptr->otab[hash(s,asize)];ptr; ptr = ptr->next)
if (!strcmp(s, ptr->name)) {
ptr->size += ssize;
ptr->num++;
return;
}
hptr->odif++;
if (!(ptr = malloc(sizeof(*ptr))))
error_memory();
if (!(ptr->name = strdup(s)))
error_memory();
ptr->num = 1;
ptr->size = ssize;
hashval = hash(s,asize);
ptr->next = hptr->otab[hashval];
hptr->otab[hashval] = ptr;
}
/* update input relay struct: */
void
update_rin(struct host *hptr, const char *s, int ssize) {
unsigned hashval;
struct rin *ptr;
if (vflag) fprintf(stderr, " updating input relay %s... ", s);
for (ptr = hptr->ritab[hash(s,rsize)];ptr;ptr = ptr->next)
if (!strcmp(s, ptr->name)) {
ptr->size += ssize;
ptr->num++;
if (vflag) fprintf(stderr, "OK\n");
return;
}
if (vflag) fprintf(stderr, "not found, adding.\n");
hptr->ridif++;
if (!(ptr = malloc(sizeof(*ptr))))
error_memory();
if (!(ptr->name = strdup(s)))
error_memory();
ptr->size = ssize;
ptr->num = 1;
hashval = hash(s,rsize);
ptr->next = hptr->ritab[hashval];
hptr->ritab[hashval] = ptr;
}
/* remove input relay structure */
void
remove_rin(struct host *hptr, const char *s, int size) {
unsigned hashval;
struct rin *ptr, *prev;
if (vflag) fprintf(stderr, " removing %s... ", s);
hashval = hash(s,rsize);
prev = NULL;
for (ptr = hptr->ritab[hashval]; ptr ; ptr = ptr->next) {
if (!strcmp(s, ptr->name)) {
ptr->num--;
ptr->size -= size;
if (ptr->num) {
if (vflag) fprintf(stderr, "OK\n");
return;
}
if (prev == NULL)
hptr->ritab[hashval] = ptr->next;
else
prev->next = ptr->next;
free(ptr->name);
free(ptr);
if (vflag) fprintf(stderr, "OK\n");
hptr->ridif--;
return;
}
prev = ptr;
}
if (vflag) fprintf(stderr, "not found\n");
}
/* update output relay struct: */
void
update_rout(struct host *hptr, const char *s, int ssize) {
unsigned hashval;
struct rout *ptr;
if (vflag) fprintf(stderr, " updating output relay %s... ", s);
for (ptr = hptr->rotab[hash(s,rsize)]; ptr; ptr=ptr->next)
if (!strcmp(s, ptr->name)) {
ptr->num++;
ptr->size += ssize;
if (vflag) fprintf(stderr, "OK\n");
return;
}
if (vflag) fprintf(stderr, "not found, adding.\n");
hptr->rodif++;
if (!(ptr = malloc(sizeof(*ptr))))
error_memory();
if (!(ptr->name = strdup(s)))
error_memory();
ptr->num = 1;
ptr->size = ssize;
hashval = hash(s,rsize);
ptr->next = hptr->rotab[hashval];
hptr->rotab[hashval] = ptr;
}
/* update message ID structure */
int
update_msgid(struct host *hptr, const char *p, const char *q, const char *s,
int m, int k, int n, int size, const char *msg) {
struct msgid *ptr;
if (vflag) fprintf(stderr, " initializing msgid %s, chain: ", s);
for (ptr = hptr->msgidtab; ptr; ptr=ptr->next) {
if (!strcmp(s, ptr->id)) {
if (vflag) fprintf(stderr, "msgid found!\n");
return(0);
}
if (vflag) fprintf(stderr, "%s, ", ptr->id);
}
if (vflag) fprintf(stderr, "\n");
if (!(ptr = malloc(sizeof(*ptr))))
error_memory();
if (!(ptr->sender = strdup(p)))
error_memory();
if (!(ptr->relay = strdup(q)))
error_memory();
if (!(ptr->id = strdup(s)))
error_memory();
if (!(ptr->msgid = strdup(msg)))
error_memory();
/* Set delivery flag as "NOT_DELIVERED": */
ptr->flag = 0;
ptr->hh = m;
ptr->day = k;
ptr->num = n;
ptr->size = size;
/* utilize next pointer: */
ptr->next = hptr->msgidtab;
hptr->msgidtab = ptr;
return(0);
}
/* get current message ID structure */
struct msgid *
get_msgid(struct host *hptr, const char *s) {
struct msgid *ptr;
if (vflag) fprintf(stderr, " getting size for msgid %s...", s);
for (ptr = hptr->msgidtab; ptr; ptr=ptr->next)
if (!strcmp(s, ptr->id)) {
if (vflag) fprintf(stderr, " %e\n", (double)ptr->size);
return(ptr);
}
if (vflag) fprintf(stderr, " not found\n");
return(NULL);
}
/* check message ID structure */
void
check_msgid(struct host *hptr, const char *s, int p) {
struct msgid *ptr, *prev;
if (!p && vflag)
fprintf(stderr, " checking %s... ", s);
prev = NULL;
for (ptr = hptr->msgidtab; ptr; ptr=ptr->next) {
if (!strcmp(s, ptr->id)) {
if (!p) {
ptr->num--;
if (vflag) fprintf(stderr,
"nr of recipients left: %d\n", ptr->num);
}
if (ptr->num < 0)
ptr->num = 0;
if (p && ptr->num == 0) {
if (vflag) fprintf(stderr,
" %s removed from chain\n", s);
if (prev == NULL)
hptr->msgidtab = ptr->next;
else
prev->next = ptr->next;
free(ptr->id);
free(ptr->sender);
free(ptr->relay);
free(ptr);
}
return;
}
prev = ptr;
}
if (!p && vflag)
fprintf(stderr, "not found\n");
}
/* remove message ID structure */
void
remove_msgid(struct host *hptr, const char *s) {
struct msgid *ptr, *prev;
if (vflag) fprintf(stderr, " removing %s... ", s);
prev = NULL;
for (ptr = hptr->msgidtab; ptr; ptr=ptr->next) {
if (!strcmp(s, ptr->id)) {
if (vflag) fprintf(stderr, "OK\n");
if (prev == NULL)
hptr->msgidtab = ptr->next;
else
prev->next = ptr->next;
free(ptr->id);
free(ptr->sender);
free(ptr->relay);
free(ptr);
return;
}
prev = ptr;
}
if (vflag) fprintf(stderr, "not found\n");
}
/* update out-of-order message ID structure */
int
update_omsgid(struct host *hptr, const char *s, int n) {
struct omsgid *ptr;
if (vflag) fprintf(stderr, " initializing omsgid %s, chain: ", s);
for (ptr = hptr->omsgidtab; ptr; ptr=ptr->next) {
if (!strcmp(s, ptr->id)) {
if (vflag) fprintf(stderr, "omsgid found!\n");
return(0);
}
if (vflag) fprintf(stderr, "%s, ", ptr->id);
}
if (vflag) fprintf(stderr, "\n");
if (!(ptr = malloc(sizeof(*ptr))))
error_memory();
if (!(ptr->id = strdup(s)))
error_memory();
ptr->flags = n;
/* utilize next pointer: */
ptr->next = hptr->omsgidtab;
hptr->omsgidtab = ptr;
return(0);
}
/* check out-of-order message ID structure */
int
check_omsgid(struct host *hptr, const char *s) {
struct omsgid *ptr, *prev;
prev = NULL;
for (ptr = hptr->omsgidtab; ptr; ptr=ptr->next) {
if (!strcmp(s, ptr->id)) {
if (vflag) fprintf(stderr, " %s removed from chain\n", s);
if (prev == NULL)
hptr->omsgidtab = ptr->next;
else
prev->next = ptr->next;
free(ptr->id);
free(ptr);
return(1);
}
prev = ptr;
}
return(0);
}
/* update status struct: */
void
update_status(struct host *hptr, const char *s) {
unsigned hashval;
struct status *ptr;
for (ptr = hptr->sttab[hash(s,rsize)];ptr; ptr = ptr->next)
if (!strcmp(s, ptr->name)) {
ptr->num++;
return;
}
hptr->sdif++;
if (!(ptr = malloc(sizeof(*ptr))))
error_memory();
if (!(ptr->name = strdup(s)))
error_memory();
ptr->num = 1;
hashval = hash(s,rsize);
ptr->next = hptr->sttab[hashval];
hptr->sttab[hashval] = ptr;
}
/* update ruleset struct: */
void
update_ruleset(struct host *hptr, const char *s, const char *p) {
unsigned hashval;
struct rule *ptr;
struct rrelay *rptr;
hashval = hash(s,rsize);
for (ptr = hptr->ruletab[hashval];ptr; ptr = ptr->next)
if (!strcmp(s, ptr->name)) {
ptr->num++;
/* Update relay table: */
for (rptr = ptr->rrelaytab; rptr; rptr = rptr->next) {
if (!strcmp(p, rptr->name)) {
rptr->num++;
return;
}
}
ptr->reldif++;
if (!(rptr = malloc(sizeof(*rptr))))
error_memory();
if (!(rptr->name = strdup(p)))
error_memory();
rptr->num = 1;
rptr->next = ptr->rrelaytab;
ptr->rrelaytab = rptr;
return;
}
/* New entry, set defaults: */
hptr->rdif++;
if (!(ptr = malloc(sizeof(*ptr))))
error_memory();
if (!(ptr->name = strdup(s)))
error_memory();
ptr->rrelaytab = NULL;
/* Set defaults for first relay */
if (!(rptr = malloc(sizeof(*rptr))))
error_memory();
if (!(rptr->name = strdup(p)))
error_memory();
rptr->num = 1;
rptr->next = ptr->rrelaytab;
ptr->rrelaytab = rptr;
ptr->num = 1;
ptr->reldif = 1;
ptr->next = hptr->ruletab[hashval];
hptr->ruletab[hashval] = ptr;
}
/* update envelope pairs: */
void
update_envpair(struct host *hptr, const char *s, const char *p, int ssize) {
unsigned hashval;
struct envpair *ptr;
const char *f;
const char *t;
char *tmp;
char *tmp1;
f = s; t = p;
if (!(tmp = malloc(strlen(s)+strlen(p))))
error_memory();
tmp1 = tmp;
while(*s != '\0') *tmp++ = *s++;
while(*p != '\0') *tmp++ = *p++;
hashval = hash(t,asize);
for (ptr = hptr->etab[hashval];ptr; ptr = ptr->next)
if (!strcmp(f, ptr->fname) && !(strcmp(t, ptr->tname))) {
ptr->num++;
ptr->size += ssize;
free(tmp1);
return;
}
hptr->edif++;
if (!(ptr = malloc(sizeof(*ptr))))
error_memory();
if (!(ptr->fname = strdup(f)))
error_memory();
if (!(ptr->tname = strdup(t)))
error_memory();
ptr->num = 1;
ptr->size = ssize;
ptr->next = hptr->etab[hashval];
hptr->etab[hashval] = ptr;
free(tmp1);
}
/* update relay pairs: */
void
update_relpair(struct host *hptr, const char *s, const char *p, int ssize) {
unsigned hashval;
struct relpair *ptr;
const char *f;
const char *t;
char *tmp;
char *tmp1;
f = s; t = p;
if (!(tmp = malloc(strlen(s)+strlen(p))))
error_memory();
tmp1 = tmp;
while(*s != '\0') *tmp++ = *s++;
while(*p != '\0') *tmp++ = *p++;
hashval = hash(t,rsize);
for (ptr = hptr->rtab[hashval];ptr; ptr = ptr->next)
if (!strcmp(f, ptr->fname) && !(strcmp(t, ptr->tname))) {
ptr->num++;
ptr->size += ssize;
free(tmp1);
return;
}
hptr->rrdif++;
if (!(ptr = malloc(sizeof(*ptr))))
error_memory();
if (!(ptr->fname = strdup(f)))
error_memory();
if (!(ptr->tname = strdup(t)))
error_memory();
ptr->num = 1;
ptr->size = ssize;
ptr->next = hptr->rtab[hashval];
hptr->rtab[hashval] = ptr;
free(tmp1);
}
syntax highlighted by Code2HTML, v. 0.9.1