/* * 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); }