/* * EnderUNIX Software Development Team, (c) 2002 * Istanbul / Turkiye */ #include #include #include #include #include #include #include #include "loadconfig.h" #include "functions.h" #include "wildmat.h" extern char mail_command[VALSIZE]; extern char makemap_command[VALSIZE]; extern char sysadmin[VALSIZE]; extern char statfile[VALSIZE]; extern char badmailfile[VALSIZE]; extern int wcnt; extern int bcnt; extern int pcnt; extern int w; extern int b; extern int p; /* check if the supplied mail address exist in our "ignored" linked list */ int isIgnored(char *email) { iaddr *l = iaddrlist; for ( ; l != NULL; l = l->next) { if (DoMatch(email, l->mail) == TRUE) return 1; } return -1; } /* Check if the email address if already in list. * If so, increment its hit count; if not, * add it to end of the list */ void check_addr(char *email) { int h; maddr *sym = NULL; /* Calculate hash sum, locate and inc. cnt if email exists, * otherwise place it in spammer_hash */ h = hash(email); for (sym = spammer_hash[h]; sym != NULL; sym = sym->next) if (strcmp(email, sym->mail) == 0) { sym->cnt++; return; } sym = (maddr *)malloc(sizeof(maddr)); /* No need a malloc for mail, because, email's been malloc'ed before */ sym->mail = email; sym->cnt = 1; sym->next = spammer_hash[h]; spammer_hash[h] = sym; return; } void addToIgnored(char *email) { iaddr *new = NULL; new = (iaddr *)malloc(sizeof(iaddr)); new->mail = email; new->next = iaddrlist; iaddrlist = new; } /* remove some unnecessary characters */ void rmspace(char *s, char *t) { while( *s != '\0') { if (*s == ' ' || *s == '\n' || *s == '\r' || *s == '\t') s++; else *t++ = *s++; } } /* notifying system administrator of spammer activity */ int send_notify_mail(char *n) { FILE *inpp; char tmpfile[BUFSIZE]; char mailcmd[BUFSIZE]; int fd, retval, ret; size_t bytes; strncpy(tmpfile, "/tmp/qstspam-XXXXXX", BUFSIZE); if ((fd = mkstemp(tmpfile)) == -1) { puts("Couldn't create temporary file name"); perror("mkstemp"); return errno; } if ((bytes = write(fd, n, strlen(n))) < bytes) { fprintf(stderr, "Couldn't write to temporary file"); return errno; } if ((ret = close(fd)) == -1) { fprintf(stderr, "Couldn't close temporary file"); perror("close"); return errno; } strcpy(mailcmd, mail_command); strcat(mailcmd, " -s \"spamGuard notification!\" "); strcat(mailcmd, sysadmin); strcat(mailcmd, " < "); strcat(mailcmd, tmpfile); if ((inpp = popen(mailcmd, "r")) == NULL) { fprintf(stderr, "Couldn't send mail"); perror("popen"); return errno; } if ((retval = pclose(inpp)) == -1) { perror("pclose"); return errno; } if ((ret = unlink(tmpfile)) == -1) { perror("unlink"); return errno; } return retval; } unsigned int hash(char *str) { unsigned int h; unsigned char *p = NULL; h = 0; for (p = (unsigned char *)str; *p != '\0'; p++) h = MULTIPLIER * h + *p; return h % MAXADDR; } void save_pos(hist_stat *h) { FILE *fp; if ((fp = fopen(statfile, "w")) == NULL) { fprintf(stderr, "Couldn't open %s: %s\n", statfile, strerror(errno)); return; } fprintf(fp, "%d %d", h->inode, h->saved_pos); if ((fclose(fp)) == -1) { fprintf(stderr, "Couldn't close %s: %s\n", statfile, strerror(errno)); return; } } void get_saved_pos(hist_stat *h) { FILE *fp; char inode[16]; char pos[16]; if ((fp = fopen(statfile, "r")) == NULL) { fprintf(stderr, "Couldn't open %s: %s\n", statfile, strerror(errno)); return; } fscanf(fp, "%s %s", inode, pos); if (inode != NULL) h->inode = atoi(inode); if (pos != NULL) h->saved_pos = atoi(pos); if ((fclose(fp)) == -1) { fprintf(stderr, "Couldn't close %s: %s\n", statfile, strerror(errno)); return; } } int makemap(void) { FILE *fp; int retval; if ((fp = popen(makemap_command, "r")) == NULL) { fprintf(stderr, "Couldn't create hash database file\n"); perror("popen"); } if ((retval = pclose(fp)) == -1) { perror("pclose"); return errno; } return retval; } /* loads ignore user list from spam-ignore.txt */ void loadIgnoreList(char *fn) { FILE *fp; char buf[1024]; char *t; t = (char *) calloc(1024, sizeof(char)); if ((fp = fopen(fn, "r")) == NULL) { fprintf(stderr, "fopen: %s: %s\n", fn, strerror(errno)); exit(-1); } memset(buf, 0, 1024); memset(t, 0, 1024); while ((fgets(buf, 1024, fp)) != NULL) { rmspace(buf, t); addToIgnored(strdup(t)); memset(t, 0, 1024); memset(buf, 0, 1024); } free(t); fclose(fp); } /* fills our ignore list. these addresses will not be treated as spammers */ void loadIgnore_sendmail(char *fn) { FILE *fp; char buf[1024]; char *m; char *t; if ((fp = fopen(fn, "r")) == NULL) { fprintf(stderr, "fopen: %s: %s\n", fn, strerror(errno)); exit(-1); } memset(buf, 0, 1024); while ((fgets(buf, 1024, fp)) != NULL) { if (buf[0] == '#' || buf[0] == ' ') continue; m = strtok(buf, "\t"); t = (char *)calloc(strlen(m), sizeof(char)); rmspace(m, t); addToIgnored(t); memset(buf, 0, 1024); } fclose(fp); } /* This function reads the logfile and fills the " from " linked list */ /* traverse "from" linked list and decide whether the hit count per mail address * exceeds the "spammer threshold" */ int qmail_finalize(void) { FILE *fp; maddr *ptr; char mailbuf[2048]; int spamcnt = 0; int i; if ((fp = fopen(badmailfile, "a+")) == NULL) { fprintf(stderr, "fopen: %s: %s\n", badmailfile, strerror(errno)); exit(-1); } for (i = 0; i < MAXADDR; i++) for (ptr = spammer_hash[i]; ptr != NULL; ptr = ptr->next) { /* printf ("mail: %s\n", ptr->mail); */ if ((ptr->cnt < bcnt) && w == 1 && (ptr->cnt >= wcnt) && (isIgnored(ptr->mail) < 0)) { printf("Light Spammer:%s sent %d mails\n", ptr->mail, ptr->cnt); sprintf(mailbuf, " %s has been spamming your box! (sent %d mails)\n This mail is to notify you that this email address sent more emails than\n your \"warning threshold\", I'm not adding it to %s\n\n -EnderUNIX spamGuard %s\n http://www.enderunix.org/spamguard\n", ptr->mail, ptr->cnt, badmailfile, VERSION); send_notify_mail(mailbuf); } else if (ptr->cnt > bcnt) { if (p == 1 && (ptr->cnt >= pcnt)) { spamcnt = 1; fprintf(fp, "%s\n", ptr->mail); printf("Paranoid Spammer:%s sent %d mails\n", ptr->mail, ptr->cnt); sprintf(mailbuf, " %s has been spamming your box! (sent %d mails)\n No matter this mail address is matched against your ignore list, or not,\n I'm still adding it to blacklist since s/he sent more mails then\n your paranoid threshold.\n\n Source mail address has been added to %s file\n Target successfully nuked!\n\n Regards,\n -EnderUNIX spamGuard %s\n http://www.enderunix.org/spamguard\n", ptr->mail, ptr->cnt, badmailfile, VERSION); send_notify_mail(mailbuf); } else if ((isIgnored(ptr->mail)) < 0) { spamcnt = 1; fprintf(fp, "%s\n", ptr->mail); printf("Spammer:%s sent %d mails\n", ptr->mail, ptr->cnt); sprintf(mailbuf, " %s has been spamming your box! (sent %d mails)\n Source mail address has been added to %s file\n Target successfully nuked!\n\n Regards,\n -EnderUNIX spamGuard %s\n http://www.enderunix.org/spamguard\n", ptr->mail, ptr->cnt, badmailfile, VERSION); send_notify_mail(mailbuf); } } } fclose(fp); return spamcnt; } int sendmail_finalize(void) { FILE *fp; maddr *ptr; char mailbuf[2048]; int spamcnt = 0; int i; if ((fp = fopen(badmailfile, "a+")) == NULL) { fprintf(stderr, "fopen: %s: %s\n", badmailfile, strerror(errno)); exit(-1); } for (i = 0; i < MAXADDR; i++) for (ptr = spammer_hash[i]; ptr != NULL; ptr = ptr->next) { if ((ptr->cnt < bcnt) && w && (ptr->cnt >= wcnt) && (isIgnored(ptr->mail) < 0)) { printf("Light Spammer:%s sent %d mails\n", ptr->mail, ptr->cnt); sprintf(mailbuf, " %s has been spamming your box! (sent %d mails)\n This mail is to notify you that this email address sent more emails than\n your \"warning threshold\", I'm not adding it to %s\n\n -EnderUNIX spamGuard %s\n http://www.enderunix.org/spamguard\n", ptr->mail, ptr->cnt, badmailfile, VERSION); send_notify_mail(mailbuf); } else if (ptr->cnt > bcnt) { if (p && (ptr->cnt >= pcnt)) { spamcnt = 1; fprintf(fp, "%s\tERROR:\"550: Your address is blocked because of spammer activity [http://www.enderunix.org/spamguard]\"\n", ptr->mail); printf("Paranoid Spammer:%s sent %d mails\n", ptr->mail, ptr->cnt); sprintf(mailbuf, " %s has been spamming your box! (sent %d mails)\n No matter this mail address is matched against your ignore list, or not,\n I'm still adding it to blacklist since s/he sent more mails then\n your paranoid threshold.\n\n Source mail address has been added to %s file\n Target successfully nuked!\n\n Regards,\n -EnderUNIX spamGuard %s\n http://www.enderunix.org/spamguard\n", ptr->mail, ptr->cnt, badmailfile, VERSION); send_notify_mail(mailbuf); } else if ((isIgnored(ptr->mail)) < 0) { spamcnt = 1; fprintf(fp, "%s\tERROR:\"550: Your address is blocked because of spammer activity [http://www.enderunix.org/spamguard]\"\n", ptr->mail); printf("Spammer:%s sent %d mails\n", ptr->mail, ptr->cnt); sprintf(mailbuf, " %s has been spamming your box! (sent %d mails)\n Source mail address has been added to %s file\n Target successfully nuked!\n\n Regards,\n -EnderUNIX spamGuard %s\n http://www.enderunix.org/spamguard\n", ptr->mail, ptr->cnt, badmailfile, VERSION); send_notify_mail(mailbuf); } } } fclose(fp); return spamcnt; } void print_list(int list) { int i; maddr *m; list = 0; for (i = 0; i < MAXADDR; i++) if (spammer_hash[i] != NULL) for (m = spammer_hash[i]; m != NULL; m = m->next) printf("%s - %d mails\n", m->mail, m->cnt); }