1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <errno.h>
4 #include <string.h>
5 #include <strings.h>
6 #include <unistd.h>
7 #include <sys/types.h>
8 #include "loadconfig.h"
9 #include "functions.h"
10 #include "wildmat.h"
11 #include "hash.h"
12
13 maddr *spammer_hash[MAXADDR];
14 iaddr *iaddrlist;
15
16 extern int w;
17 extern int b;
18 extern int p;
19
20 int
is_ignored(char * email,char src)21 is_ignored(char *email, char src)
22 {
23 iaddr *l = iaddrlist;
24
25 for ( ; l != NULL; l = l->next) {
26 if (src & l->src)
27 if (DoMatch(email, l->mail, strlen(l->mail)) == TRUE)
28 return 1;
29 }
30 return 0;
31 }
32
33 void
check_addr(char * email)34 check_addr(char *email)
35 {
36 int h = 0;
37 maddr *sym = NULL;
38
39 if(strncmp(email, "#@[]", 4) == 0)
40 return;
41
42 h = cdbhash(email, sizeof(email));
43 for (sym = spammer_hash[h]; sym != NULL; sym = sym->next)
44 if (strncmp(email, sym->mail, sizeof(email)-1) == 0) {
45 sym->cnt++;
46 return;
47 }
48
49 sym = (maddr *)malloc(sizeof(maddr));
50 sym->mail = email;
51 sym->cnt = 1;
52 sym->next = spammer_hash[h];
53 spammer_hash[h] = sym;
54 return;
55 }
56
57 void
add_ignored(char * email,char src)58 add_ignored(char *email, char src)
59 {
60
61 iaddr *new = NULL;
62
63 new = (iaddr *)malloc(sizeof(iaddr));
64 new->mail = email;
65 new->src = src;
66 new->next = iaddrlist;
67 iaddrlist = new;
68 }
69
70 int
removespaces(char * buf,int len)71 removespaces(char *buf, int len)
72 {
73 char *cp = buf;
74 char *sv = buf;
75
76 for (; *buf != '\0' && ((buf - sv) < len); buf++)
77 if (*buf == ' ' || *buf == '<' || *buf == '>' || *buf == '\n' || *buf == '\r' || *buf == '\t')
78 continue;
79 else
80 *cp++ = *buf;
81 *cp = '\0';
82 return cp - sv;
83 }
84
85
86 int
send_notify_mail(char * n,char * sender,char * spam_type)87 send_notify_mail(char *n, char *sender, char *spam_type)
88 {
89
90 FILE *inpp = NULL;
91 char tmpfile[BUFSIZE];
92 char mailcmd[BUFSIZE];
93 int fd = 0, retval = 0, ret = 0;
94 size_t bytes = 0;
95
96 strncpy(tmpfile, "/tmp/qstspam-XXXXXX", BUFSIZE - 1);
97 if ((fd = mkstemp(tmpfile)) == -1) {
98 puts("Couldn't create temporary file name");
99 perror("mkstemp");
100 return errno;
101 }
102
103 bytes = strlen(n);
104 if (write(fd, n, bytes) < bytes) {
105 fprintf(stderr, "Couldn't write to temporary file");
106 return errno;
107 }
108
109 if ((ret = close(fd)) == -1) {
110 fprintf(stderr, "Couldn't close temporary file");
111 perror("close");
112 return errno;
113 }
114
115 strncpy(mailcmd, mail_command, BUFSIZE - 1);
116 strncat(mailcmd, " -s \"spamGuard notification ", BUFSIZE - 1);
117 strncat(mailcmd, spam_type, BUFSIZE - 1);
118 strncat(mailcmd, sender, BUFSIZE - 1);
119 strncat(mailcmd, " \" ", BUFSIZE - 1);
120 strncat(mailcmd, sysadmin, BUFSIZE - 1);
121 strncat(mailcmd, " < ", BUFSIZE - 1);
122 strncat(mailcmd, tmpfile, BUFSIZE - 1);
123
124 if ((inpp = popen(mailcmd, "r")) == NULL) {
125 fprintf(stderr, "Couldn't send mail");
126 perror("popen");
127 return errno;
128 }
129
130 if ((retval = pclose(inpp)) == -1) {
131 perror("pclose");
132 return errno;
133 }
134
135 if ((ret = unlink(tmpfile)) == -1) {
136 perror("unlink");
137 return errno;
138 }
139
140 return retval;
141 }
142
143 void
save_pos(hist_stat * h)144 save_pos(hist_stat *h)
145 {
146 FILE *fp = NULL;
147
148 if (h == NULL)
149 return;
150
151 if ((fp = fopen(statfile, "w")) == NULL) {
152 fprintf(stderr, "Couldn't open %s: %s\n", statfile, strerror(errno));
153 return;
154 }
155
156 fprintf(fp, "%d %d", h->inode, h->saved_pos);
157 if ((fclose(fp)) == -1) {
158 fprintf(stderr, "Couldn't close %s: %s\n", statfile, strerror(errno));
159 return;
160 }
161 }
162
163 void
get_saved_pos(hist_stat * h)164 get_saved_pos(hist_stat *h)
165 {
166 FILE *fp = NULL;
167 char inode[16];
168 char pos[16];
169
170 if (h == NULL)
171 return;
172
173 if ((fp = fopen(statfile, "r")) == NULL) {
174 fprintf(stderr, "Couldn't open %s: %s\n", statfile, strerror(errno));
175 return;
176 }
177
178 fscanf(fp, "%15s %15s", inode, pos);
179
180 if (inode != NULL)
181 h->inode = atoi(inode);
182
183 if (pos != NULL)
184 h->saved_pos = atoi(pos);
185
186 if ((fclose(fp)) == -1) {
187 fprintf(stderr, "Couldn't close %s: %s\n", statfile, strerror(errno));
188 return;
189 }
190 }
191
192 int
makemap(void)193 makemap(void)
194 {
195 FILE *fp = NULL;
196 int retval = 0;
197
198 if ((fp = popen(makemap_command, "r")) == NULL) {
199 fprintf(stderr, "Couldn't create hash database file\n");
200 perror("popen");
201 }
202
203 if ((retval = pclose(fp)) == -1) {
204 perror("pclose");
205 return errno;
206 }
207
208 return retval;
209 }
210
211 void
load_ignore_list(char * fn,char src)212 load_ignore_list(char *fn, char src)
213 {
214
215 FILE *fp = NULL;
216 char buf[1024];
217
218 if ((fp = fopen(fn, "r")) == NULL) {
219 fprintf(stderr, "fopen: %s: %s\n", fn, strerror(errno));
220 exit(-1);
221 }
222
223 memset(buf, 0x0, sizeof(buf));
224 while ((fgets(buf, 1024, fp)) != NULL) {
225 removespaces(buf, strlen(buf));
226 add_ignored(strdup(buf), src);
227 memset(buf, 0x0, sizeof(buf));
228 }
229
230 if (fclose(fp) != 0) {
231 fprintf(stderr, "File: %s - Line: %d: %s.\n", __FILE__, __LINE__, strerror(errno));
232 exit(-1);
233 }
234 }
235
236 void
load_ignore_sendmail(char * fn,char src)237 load_ignore_sendmail(char *fn, char src)
238 {
239
240 FILE *fp = NULL;
241 char buf[1024];
242 char *m = NULL;
243
244 if ((fp = fopen(fn, "r")) == NULL) {
245 fprintf(stderr, "fopen: %s: %s\n", fn, strerror(errno));
246 exit(-1);
247 }
248
249 memset(buf, 0, sizeof(buf));
250 while ((fgets(buf, 1024, fp)) != NULL) {
251 if (buf[0] == '#' || buf[0] == ' ')
252 continue;
253 m = strtok(buf, "\t");
254 if (m == NULL)
255 continue;
256 removespaces(m, strlen(m));
257 add_ignored(strdup(m), src);
258 memset(buf, 0, sizeof(buf));
259 }
260
261 if (fclose(fp) != 0){
262 fprintf(stderr, "File: %s - Line: %d: %s.\n", __FILE__, __LINE__, strerror(errno));
263 exit(-1);
264 }
265 }
266
267 int
qmail_finalize(void)268 qmail_finalize(void)
269 {
270
271 FILE *fp = NULL;
272 maddr *ptr = NULL;
273 char mailbuf[2048];
274 int i = 0, spamcnt = 0;
275
276 if ((fp = fopen(badmailfile, "a+")) == NULL) {
277 fprintf(stderr, "fopen: %s: %s\n", badmailfile, strerror(errno));
278 exit(-1);
279 }
280
281 for (i = 0; i < MAXADDR; i++)
282 for (ptr = spammer_hash[i]; ptr != NULL; ptr = ptr->next) {
283 if ((ptr->cnt < bcnt) && w == 1 && (ptr->cnt >= wcnt) && (!is_ignored(ptr->mail, SRC_ALL))) {
284 printf("Light Spammer:%s sent %d mails\n", ptr->mail, ptr->cnt);
285 snprintf(mailbuf, 2047, " %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);
286 mailbuf[sizeof(mailbuf) - 1] = '\0';
287 send_notify_mail(mailbuf, ptr->mail, "warning ");
288 }
289
290 else if (ptr->cnt >= bcnt) {
291 if (p == 1 && (ptr->cnt >= pcnt) && (!is_ignored(ptr->mail, SRC_BADMAILFROM))
292 && (!is_ignored(ptr->mail, SRC_IGNOREFILE))) {
293 spamcnt = 1;
294 fprintf(fp, "%s\n", ptr->mail);
295 printf("Paranoid Spammer:%s sent %d mails\n", ptr->mail, ptr->cnt);
296 snprintf(mailbuf, 2047, " %s has been spamming your box! (sent %d mails)\n No matter this mail address is matched against your spam high list: %s, or not. I'm still adding it to blacklist since s/he sent more mails then 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, highfile, badmailfile, VERSION);
297 mailbuf[sizeof(mailbuf) - 1] = '\0';
298 send_notify_mail(mailbuf, ptr->mail, "paronaid ");
299 }
300 else if (!is_ignored(ptr->mail, SRC_ALL)) {
301 spamcnt = 1;
302 fprintf(fp, "%s\n", ptr->mail);
303 printf("Spammer:%s sent %d mails\n", ptr->mail, ptr->cnt);
304 snprintf(mailbuf, 2047, " %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);
305 mailbuf[sizeof(mailbuf) - 1] = '\0';
306 send_notify_mail(mailbuf, ptr->mail, "blocked ");
307 }
308 }
309 }
310 if (fclose(fp) != 0) {
311 fprintf(stderr, "File: %s - Line: %d: %s.\n", __FILE__, __LINE__, strerror(errno));
312 exit(-1);
313 }
314
315 return spamcnt;
316 }
317
318 int
sendmail_finalize(void)319 sendmail_finalize(void)
320 {
321
322 FILE *fp = NULL;
323 maddr *ptr = NULL;
324 char mailbuf[2048];
325 int i = 0, spamcnt = 0;
326
327 if ((fp = fopen(badmailfile, "a+")) == NULL) {
328 fprintf(stderr, "fopen: %s: %s\n", badmailfile, strerror(errno));
329 exit(-1);
330 }
331
332 for (i = 0; i < MAXADDR; i++)
333 for (ptr = spammer_hash[i]; ptr != NULL; ptr = ptr->next) {
334 if ((ptr->cnt < bcnt) && w && (ptr->cnt >= wcnt) && (!is_ignored(ptr->mail, SRC_ALL))) {
335 printf("Light Spammer:%s sent %d mails\n", ptr->mail, ptr->cnt);
336 snprintf(mailbuf, 2047, " %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);
337 mailbuf[sizeof(mailbuf) - 1] = '\0';
338 send_notify_mail(mailbuf, ptr->mail, "warning ");
339 }
340
341 else if (ptr->cnt >= bcnt) {
342 if (p == 1 && (ptr->cnt >= pcnt) && (!is_ignored(ptr->mail, SRC_BADMAILFROM))
343 && (!is_ignored(ptr->mail, SRC_IGNOREFILE))) {
344 spamcnt = 1;
345 fprintf(fp, "%s\tERROR:\"550: Your address is blocked because of spammer activity [http://www.enderunix.org/spamguard]\"\n", ptr->mail);
346 printf("Paranoid Spammer:%s sent %d mails\n", ptr->mail, ptr->cnt);
347 snprintf(mailbuf, 2047, " %s has been spamming your box! (sent %d mails)\n No matter this mail address is matched against your high list:%s, or not. I'm still adding it to blacklist since s/he sent more mails then 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, highfile, badmailfile, VERSION);
348 mailbuf[sizeof(mailbuf) - 1] = '\0';
349 send_notify_mail(mailbuf, ptr->mail, "paranoid ");
350 }
351 else if (!is_ignored(ptr->mail, SRC_ALL)) {
352 spamcnt = 1;
353 fprintf(fp, "%s\tERROR:\"550: Your address is blocked because of spammer activity [http://www.enderunix.org/spamguard]\"\n", ptr->mail);
354 printf("Spammer:%s sent %d mails\n", ptr->mail, ptr->cnt);
355 snprintf(mailbuf, 2047, " %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);
356 mailbuf[sizeof(mailbuf) - 1] = '\0';
357 send_notify_mail(mailbuf, ptr->mail, "blocked ");
358 }
359 }
360 }
361 if (fclose(fp) != 0) {
362 fprintf(stderr, "File: %s - Line: %d: %s.\n", __FILE__, __LINE__, strerror(errno));
363 exit(-1);
364 }
365
366 return spamcnt;
367 }
368
369 void
print_list(int list)370 print_list(int list)
371 {
372 int i = 0;
373 maddr *m = NULL;
374 list = 0;
375
376 for (i = 0; i < MAXADDR; i++)
377 if (spammer_hash[i] != NULL)
378 for (m = spammer_hash[i]; m != NULL; m = m->next)
379 printf("%s - %d mails\n", m->mail, m->cnt);
380 }
381