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