|
|
1.1 root 1: /* mailsrvr.c */
2:
3: /* Synchronet Mail (SMTP/POP3) server and sendmail threads */
4:
5: /* $Id: mailsrvr.c,v 1.412 2006/12/29 01:23:05 rswindell Exp $ */
6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
11: * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html *
12: * *
13: * This program is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU General Public License for more details: gpl.txt or *
18: * http://www.fsf.org/copyleft/gpl.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: /* ANSI C Library headers */
39: #include <stdio.h>
40: #include <stdlib.h> /* ltoa in GNU C lib */
41: #include <stdarg.h> /* va_list */
42: #include <string.h> /* strrchr */
43: #include <ctype.h> /* isdigit */
44: #include <fcntl.h> /* Open flags */
45: #include <errno.h> /* errno */
46:
47: /* Synchronet-specific headers */
48: #undef SBBS /* this shouldn't be defined unless building sbbs.dll/libsbbs.so */
49: #include "sbbs.h"
50: #include "mailsrvr.h"
51: #include "mime.h"
52: #include "md5.h"
53: #include "crc32.h"
54: #include "base64.h"
55: #include "ini_file.h"
56: #include "netwrap.h" /* getNameServerList() */
57:
58: /* Constants */
59: #define FORWARD "forward:"
60: #define NO_FORWARD "local:"
61:
62: int dns_getmx(char* name, char* mx, char* mx2
63: ,DWORD intf, DWORD ip_addr, BOOL use_tcp, int timeout);
64:
65: static char* pop_err = "-ERR";
66: static char* ok_rsp = "250 OK";
67: static char* auth_ok = "235 User Authenticated";
68: static char* sys_error = "421 System error";
69: static char* sys_unavail= "421 System unavailable, try again later";
70: static char* badarg_rsp = "501 Bad argument";
71: static char* badseq_rsp = "503 Bad sequence of commands";
72: static char* badauth_rsp= "535 Authentication failure";
73: static char* badrsp_err = "%s replied with:\r\n\"%s\"\r\n"
74: "instead of the expected reply:\r\n\"%s ...\"";
75:
76: #define TIMEOUT_THREAD_WAIT 60 /* Seconds */
77: #define DNSBL_THROTTLE_VALUE 5000 /* Milliseconds */
78:
79: #define STATUS_WFC "Listening"
80:
81: static mail_startup_t* startup=NULL;
82: static scfg_t scfg;
83: static SOCKET server_socket=INVALID_SOCKET;
84: static SOCKET pop3_socket=INVALID_SOCKET;
85: static DWORD active_clients=0;
86: static int active_sendmail=0;
87: static DWORD thread_count=0;
88: static BOOL sendmail_running=FALSE;
89: static DWORD sockets=0;
90: static DWORD served=0;
91: static BOOL terminate_server=FALSE;
92: static BOOL terminate_sendmail=FALSE;
93: static sem_t sendmail_wakeup_sem;
94: static char revision[16];
95: static time_t uptime;
96: static str_list_t recycle_semfiles;
97: static str_list_t shutdown_semfiles;
98: static int mailproc_count;
99:
100: struct mailproc {
101: char cmdline[INI_MAX_VALUE_LEN];
102: str_list_t to;
103: BOOL passthru;
104: BOOL native;
105: } *mailproc_list;
106:
107: typedef struct {
108: SOCKET socket;
109: SOCKADDR_IN client_addr;
110: } smtp_t,pop3_t;
111:
112: static int lprintf(int level, char *fmt, ...)
113: {
114: va_list argptr;
115: char sbuf[1024];
116:
117: if(startup==NULL || startup->lputs==NULL)
118: return(0);
119:
120: va_start(argptr,fmt);
121: vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
122: sbuf[sizeof(sbuf)-1]=0;
123: va_end(argptr);
124: return(startup->lputs(startup->cbdata,level,sbuf));
125: }
126:
127: #ifdef _WINSOCKAPI_
128:
129: static WSADATA WSAData;
130: #define SOCKLIB_DESC WSAData.szDescription
131: static BOOL WSAInitialized=FALSE;
132:
133: static BOOL winsock_startup(void)
134: {
135: int status; /* Status Code */
136:
137: if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0) {
138: lprintf(LOG_INFO,"%s %s",WSAData.szDescription, WSAData.szSystemStatus);
139: WSAInitialized=TRUE;
140: return (TRUE);
141: }
142:
143: lprintf(LOG_CRIT,"!WinSock startup ERROR %d", status);
144: return (FALSE);
145: }
146:
147: #else /* No WINSOCK */
148:
149: #define winsock_startup() (TRUE)
150: #define SOCKLIB_DESC NULL
151:
152: #endif
153:
154: static void update_clients(void)
155: {
156: if(startup!=NULL && startup->clients!=NULL)
157: startup->clients(startup->cbdata,active_clients+active_sendmail);
158: }
159:
160: static void client_on(SOCKET sock, client_t* client, BOOL update)
161: {
162: if(startup!=NULL && startup->client_on!=NULL)
163: startup->client_on(startup->cbdata,TRUE,sock,client,update);
164: }
165:
166: static void client_off(SOCKET sock)
167: {
168: if(startup!=NULL && startup->client_on!=NULL)
169: startup->client_on(startup->cbdata,FALSE,sock,NULL,FALSE);
170: }
171:
172: static void thread_up(BOOL setuid)
173: {
174: thread_count++;
175: if(startup!=NULL && startup->thread_up!=NULL)
176: startup->thread_up(startup->cbdata,TRUE,setuid);
177: }
178:
179: static void thread_down(void)
180: {
181: if(thread_count>0)
182: thread_count--;
183: if(startup!=NULL && startup->thread_up!=NULL)
184: startup->thread_up(startup->cbdata,FALSE,FALSE);
185: }
186:
187: SOCKET mail_open_socket(int type, const char* protocol)
188: {
189: char error[256];
190: char section[128];
191: SOCKET sock;
192:
193: sock=socket(AF_INET, type, IPPROTO_IP);
194: if(sock!=INVALID_SOCKET && startup!=NULL && startup->socket_open!=NULL)
195: startup->socket_open(startup->cbdata,TRUE);
196: if(sock!=INVALID_SOCKET) {
197: SAFEPRINTF(section,"mail|%s",protocol);
198: if(set_socket_options(&scfg, sock, section, error, sizeof(error)))
199: lprintf(LOG_ERR,"%04d !ERROR %s",sock,error);
200:
201: sockets++;
202: #if 0 /*def _DEBUG */
203: lprintf(LOG_DEBUG,"%04d Socket opened (%d sockets in use)",sock,sockets);
204: #endif
205: }
206: return(sock);
207: }
208:
209: int mail_close_socket(SOCKET sock)
210: {
211: int result;
212:
213: if(sock==INVALID_SOCKET)
214: return(-1);
215:
216: shutdown(sock,SHUT_RDWR); /* required on Unix */
217: result=closesocket(sock);
218: if(startup!=NULL && startup->socket_open!=NULL)
219: startup->socket_open(startup->cbdata,FALSE);
220: sockets--;
221: if(result!=0) {
222: if(ERROR_VALUE!=ENOTSOCK)
223: lprintf(LOG_ERR,"%04d !ERROR %d closing socket",sock, ERROR_VALUE);
224: }
225: #if 0 /*def _DEBUG */
226: else
227: lprintf(LOG_DEBUG,"%04d Socket closed (%d sockets in use)",sock,sockets);
228: #endif
229:
230: return(result);
231: }
232:
233: static void status(char* str)
234: {
235: if(startup!=NULL && startup->status!=NULL)
236: startup->status(startup->cbdata,str);
237: }
238:
239: int sockprintf(SOCKET sock, char *fmt, ...)
240: {
241: int len;
242: int maxlen;
243: int result;
244: va_list argptr;
245: char sbuf[1024];
246: fd_set socket_set;
247: struct timeval tv;
248:
249: va_start(argptr,fmt);
250: len=vsnprintf(sbuf,maxlen=sizeof(sbuf)-2,fmt,argptr);
251: va_end(argptr);
252:
253: if(len<0 || len > maxlen) /* format error or output truncated */
254: len=maxlen;
255: if(startup->options&MAIL_OPT_DEBUG_TX)
256: lprintf(LOG_DEBUG,"%04d TX: %.*s", sock, len, sbuf);
257: memcpy(sbuf+len,"\r\n",2);
258: len+=2;
259:
260: if(sock==INVALID_SOCKET) {
261: lprintf(LOG_WARNING,"!INVALID SOCKET in call to sockprintf");
262: return(0);
263: }
264:
265: /* Check socket for writability (using select) */
266: tv.tv_sec=300;
267: tv.tv_usec=0;
268:
269: FD_ZERO(&socket_set);
270: FD_SET(sock,&socket_set);
271:
272: if((result=select(sock+1,NULL,&socket_set,NULL,&tv))<1) {
273: if(result==0)
274: lprintf(LOG_NOTICE,"%04d !TIMEOUT selecting socket for send"
275: ,sock);
276: else
277: lprintf(LOG_NOTICE,"%04d !ERROR %d selecting socket for send"
278: ,sock, ERROR_VALUE);
279: return(0);
280: }
281:
282: while((result=sendsocket(sock,sbuf,len))!=len) {
283: if(result==SOCKET_ERROR) {
284: if(ERROR_VALUE==EWOULDBLOCK) {
285: YIELD();
286: continue;
287: }
288: if(ERROR_VALUE==ECONNRESET)
289: lprintf(LOG_NOTICE,"%04d Connection reset by peer on send",sock);
290: else if(ERROR_VALUE==ECONNABORTED)
291: lprintf(LOG_NOTICE,"%04d Connection aborted by peer on send",sock);
292: else
293: lprintf(LOG_NOTICE,"%04d !ERROR %d sending on socket",sock,ERROR_VALUE);
294: return(0);
295: }
296: lprintf(LOG_WARNING,"%04d !ERROR: short send on socket: %d instead of %d",sock,result,len);
297: }
298: return(len);
299: }
300:
301: static time_t checktime(void)
302: {
303: struct tm tm;
304:
305: memset(&tm,0,sizeof(tm));
306: tm.tm_year=94;
307: tm.tm_mday=1;
308: return(mktime(&tm)-0x2D24BD00L);
309: }
310:
311: static void recverror(SOCKET socket, int rd, int line)
312: {
313: if(rd==0)
314: lprintf(LOG_NOTICE,"%04d Socket closed by peer on receive (line %d)"
315: ,socket, line);
316: else if(rd==SOCKET_ERROR) {
317: if(ERROR_VALUE==ECONNRESET)
318: lprintf(LOG_NOTICE,"%04d Connection reset by peer on receive (line %d)"
319: ,socket, line);
320: else if(ERROR_VALUE==ECONNABORTED)
321: lprintf(LOG_NOTICE,"%04d Connection aborted by peer on receive (line %d)"
322: ,socket, line);
323: else
324: lprintf(LOG_NOTICE,"%04d !ERROR %d receiving on socket (line %d)"
325: ,socket, ERROR_VALUE, line);
326: } else
327: lprintf(LOG_WARNING,"%04d !ERROR: recv on socket returned unexpected value: %d (line %d)"
328: ,socket, rd, line);
329: }
330:
331:
332: static int sockreadline(SOCKET socket, char* buf, int len)
333: {
334: char ch;
335: int i,rd=0;
336: fd_set socket_set;
337: struct timeval tv;
338: time_t start;
339:
340: buf[0]=0;
341:
342: start=time(NULL);
343:
344: if(socket==INVALID_SOCKET) {
345: lprintf(LOG_WARNING,"!INVALID SOCKET in call to sockreadline");
346: return(-1);
347: }
348:
349: while(rd<len-1) {
350:
351: if(server_socket==INVALID_SOCKET || terminate_server) {
352: lprintf(LOG_WARNING,"%04d !ABORTING sockreadline",socket);
353: return(-1);
354: }
355:
356: tv.tv_sec=startup->max_inactivity;
357: tv.tv_usec=0;
358:
359: FD_ZERO(&socket_set);
360: FD_SET(socket,&socket_set);
361:
362: i=select(socket+1,&socket_set,NULL,NULL,&tv);
363:
364: if(i<1) {
365: if(i==0) {
366: if((time(NULL)-start)>startup->max_inactivity) {
367: lprintf(LOG_WARNING,"%04d !SOCKET INACTIVE",socket);
368: return(-1);
369: }
370: continue;
371: }
372: recverror(socket,i,__LINE__);
373: return(-1);
374: }
375: i=recv(socket, &ch, 1, 0);
376: if(i<1) {
377: recverror(socket,i,__LINE__);
378: return(-1);
379: }
380: if(ch=='\n' /* && rd>=1 */ ) { /* Mar-9-2003: terminate on sole LF */
381: break;
382: }
383: buf[rd++]=ch;
384: }
385: if(rd>0 && buf[rd-1]=='\r')
386: rd--;
387: buf[rd]=0;
388:
389: return(rd);
390: }
391:
392: static BOOL sockgetrsp(SOCKET socket, char* rsp, char *buf, int len)
393: {
394: int rd;
395:
396: while(1) {
397: rd = sockreadline(socket, buf, len);
398: if(rd<1)
399: return(FALSE);
400: if(buf[3]=='-') { /* Multi-line response */
401: if(startup->options&MAIL_OPT_DEBUG_RX_RSP)
402: lprintf(LOG_DEBUG,"%04d RX: %s",socket,buf);
403: continue;
404: }
405: if(rsp!=NULL && strnicmp(buf,rsp,strlen(rsp))) {
406: lprintf(LOG_WARNING,"%04d !INVALID RESPONSE: '%s' Expected: '%s'", socket, buf, rsp);
407: return(FALSE);
408: }
409: break;
410: }
411: if(startup->options&MAIL_OPT_DEBUG_RX_RSP)
412: lprintf(LOG_DEBUG,"%04d RX: %s",socket,buf);
413: return(TRUE);
414: }
415:
416: #define MAX_LINE_LEN 1000
417:
418: static ulong sockmimetext(SOCKET socket, smbmsg_t* msg, char* msgtxt, ulong maxlines
419: ,str_list_t file_list, char* mime_boundary)
420: {
421: char toaddr[256]="";
422: char fromaddr[256]="";
423: char fromhost[256];
424: char date[64];
425: char* p;
426: char* tp;
427: char* content_type=NULL;
428: int i;
429: int s;
430: ulong lines;
431:
432: /* HEADERS (in recommended order per RFC822 4.1) */
433: if(!sockprintf(socket,"Date: %s",msgdate(msg->hdr.when_written,date)))
434: return(0);
435:
436: if((p=smb_get_hfield(msg,RFC822FROM,NULL))!=NULL)
437: s=sockprintf(socket,"From: %s",p); /* use original RFC822 header field */
438: else {
439: if(msg->from_net.type==NET_QWK && msg->from_net.addr!=NULL)
440: SAFEPRINTF2(fromaddr,"%s!%s"
441: ,(char*)msg->from_net.addr
442: ,usermailaddr(&scfg,fromhost,msg->from));
443: else if(msg->from_net.type==NET_FIDO && msg->from_net.addr!=NULL)
444: SAFECOPY(fromaddr,smb_faddrtoa((faddr_t *)msg->from_net.addr,NULL));
445: else if(msg->from_net.type!=NET_NONE && msg->from_net.addr!=NULL)
446: SAFECOPY(fromaddr,(char*)msg->from_net.addr);
447: else
448: usermailaddr(&scfg,fromaddr,msg->from);
449: if(fromaddr[0]=='<')
450: s=sockprintf(socket,"From: \"%s\" %s",msg->from,fromaddr);
451: else
452: s=sockprintf(socket,"From: \"%s\" <%s>",msg->from,fromaddr);
453: }
454: if(!s)
455: return(0);
456:
457: if(msg->from_org!=NULL || msg->from_net.type==NET_NONE)
458: if(!sockprintf(socket,"Organization: %s"
459: ,msg->from_org==NULL ? scfg.sys_name : msg->from_org))
460: return(0);
461:
462: if(!sockprintf(socket,"Subject: %s",msg->subj))
463: return(0);
464:
465: if((p=smb_get_hfield(msg,RFC822TO,NULL))!=NULL)
466: s=sockprintf(socket,"To: %s",p); /* use original RFC822 header field */
467: else {
468: if(strchr(msg->to,'@')!=NULL || msg->to_net.addr==NULL)
469: s=sockprintf(socket,"To: %s",msg->to); /* Avoid double-@ */
470: else if(msg->to_net.type==NET_INTERNET || msg->to_net.type==NET_QWK) {
471: if(strchr((char*)msg->to_net.addr,'<')!=NULL)
472: s=sockprintf(socket,"To: %s",(char*)msg->to_net.addr);
473: else
474: s=sockprintf(socket,"To: \"%s\" <%s>",msg->to,(char*)msg->to_net.addr);
475: } else {
476: usermailaddr(&scfg,toaddr,msg->to);
477: s=sockprintf(socket,"To: \"%s\" <%s>",msg->to,toaddr);
478: }
479: }
480: if(!s)
481: return(0);
482: if((p=smb_get_hfield(msg,RFC822REPLYTO,NULL))==NULL) {
483: if(msg->replyto_net.type==NET_INTERNET)
484: p=msg->replyto_net.addr;
485: else if(msg->replyto!=NULL)
486: p=msg->replyto;
487: }
488: if(p!=NULL)
489: s=sockprintf(socket,"Reply-To: %s",p); /* use original RFC822 header field */
490: if(!s)
491: return(0);
492: if(!sockprintf(socket,"Message-ID: %s",get_msgid(&scfg,INVALID_SUB,msg)))
493: return(0);
494: if(msg->reply_id!=NULL)
495: if(!sockprintf(socket,"In-Reply-To: %s",msg->reply_id))
496: return(0);
497:
498: for(i=0;i<msg->total_hfields;i++) {
499: if(msg->hfield[i].type==RFC822HEADER) {
500: if(strnicmp((char*)msg->hfield_dat[i],"Content-Type:",13)==0)
501: content_type=msg->hfield_dat[i];
502: if(!sockprintf(socket,"%s",(char*)msg->hfield_dat[i]))
503: return(0);
504: }
505: }
506: /* Default MIME Content-Type for non-Internet messages */
507: if(msg->from_net.type!=NET_INTERNET && content_type==NULL && startup->default_charset[0]) {
508: /* No content-type specified, so assume IBM code-page 437 (full ex-ASCII) */
509: sockprintf(socket,"Content-Type: text/plain; charset=%s", startup->default_charset);
510: sockprintf(socket,"Content-Transfer-Encoding: 8bit");
511: }
512:
513: if(strListCount(file_list)) { /* File attachments */
514: mimeheaders(socket,mime_boundary);
515: sockprintf(socket,"");
516: mimeblurb(socket,mime_boundary);
517: sockprintf(socket,"");
518: mimetextpartheader(socket,mime_boundary);
519: }
520: if(!sockprintf(socket,"")) /* Header Terminator */
521: return(0);
522:
523: /* MESSAGE BODY */
524: lines=0;
525: #if 0 /* This is now handled in smb_getmsgtxt() */
526: for(i=0;i<msg->total_hfields;i++) { /* delivery failure notification? */
527: if(msg->hfield[i].type==SMTPSYSMSG || msg->hfield[i].type==SMB_COMMENT) {
528: if(!sockprintf(socket,"%s",(char*)msg->hfield_dat[i]))
529: return(0);
530: lines++;
531: }
532: }
533: #endif
534: p=msgtxt;
535: while(*p && lines<maxlines) {
536: tp=strchr(p,'\n');
537: if(tp) {
538: if(tp-p>MAX_LINE_LEN)
539: tp=p+MAX_LINE_LEN;
540: *tp=0;
541: }
542: truncsp(p); /* Takes care of '\r' or spaces */
543: if(*p=='.')
544: i=sockprintf(socket,".%.*s",MAX_LINE_LEN,p);
545: else
546: i=sockprintf(socket,"%.*s",MAX_LINE_LEN,p);
547: if(!i)
548: break;
549: if(tp==NULL)
550: break;
551: p=tp+1;
552: lines++;
553: /* release time-slices every x lines */
554: if(startup->lines_per_yield
555: && !(lines%startup->lines_per_yield))
556: YIELD();
557: }
558: if(file_list!=NULL) {
559: for(i=0;file_list[i];i++) {
560: sockprintf(socket,"");
561: lprintf(LOG_INFO,"%04u MIME Encoding and sending %s",socket,file_list[i]);
562: if(!mimeattach(socket,mime_boundary,file_list[i]))
563: lprintf(LOG_ERR,"%04u !ERROR opening/encoding/sending %s",socket,file_list[i]);
564: else {
565: endmime(socket,mime_boundary);
566: if(msg->hdr.auxattr&MSG_KILLFILE)
567: if(remove(file_list[i])!=0)
568: lprintf(LOG_WARNING,"%04u !ERROR %d removing %s",socket,errno,file_list[i]);
569: }
570: }
571: }
572: sockprintf(socket,"."); /* End of text */
573: return(lines);
574: }
575:
576: static ulong sockmsgtxt(SOCKET socket, smbmsg_t* msg, char* msgtxt, ulong maxlines)
577: {
578: char filepath[MAX_PATH+1];
579: ulong retval;
580: char* boundary=NULL;
581: unsigned i;
582: str_list_t file_list=NULL;
583: str_list_t split;
584:
585: if(msg->hdr.auxattr&MSG_FILEATTACH) {
586:
587: boundary = mimegetboundary();
588: file_list = strListInit();
589:
590: /* Parse header fields */
591: for(i=0;i<msg->total_hfields;i++)
592: if(msg->hfield[i].type==FILEATTACH)
593: strListPush(&file_list,(char*)msg->hfield_dat[i]);
594:
595: /* Parse subject (if necessary) */
596: if(!strListCount(file_list)) { /* filename(s) stored in subject */
597: split=strListSplitCopy(NULL,msg->subj," ");
598: if(split!=NULL) {
599: for(i=0;split[i];i++) {
600: if(msg->idx.to!=0)
601: SAFEPRINTF3(filepath,"%sfile/%04u.in/%s"
602: ,scfg.data_dir,msg->idx.to,getfname(truncsp(split[i])));
603: else
604: SAFEPRINTF3(filepath,"%sfile/%04u.out/%s"
605: ,scfg.data_dir,msg->idx.from,getfname(truncsp(split[i])));
606: strListPush(&file_list,filepath);
607: }
608: strListFree(&split);
609: }
610: }
611: }
612:
613: retval = sockmimetext(socket,msg,msgtxt,maxlines,file_list,boundary);
614:
615: strListFree(&file_list);
616:
617: if(boundary!=NULL)
618: free(boundary);
619:
620: return(retval);
621: }
622:
623: static u_long resolve_ip(char *inaddr)
624: {
625: char* p;
626: char* addr;
627: char buf[128];
628: HOSTENT* host;
629:
630: SAFECOPY(buf,inaddr);
631: addr=buf;
632: if(*addr=='[' && *(p=lastchar(addr))==']') { /* Support [ip_address] notation */
633: addr++;
634: *p=0;
635: }
636:
637: if(*addr==0)
638: return((u_long)INADDR_NONE);
639:
640: for(p=addr;*p;p++)
641: if(*p!='.' && !isdigit(*p))
642: break;
643: if(!(*p))
644: return(inet_addr(addr));
645:
646: if((host=gethostbyname(inaddr))==NULL) {
647: lprintf(LOG_WARNING,"0000 !ERROR resolving hostname: %s",inaddr);
648: return((u_long)INADDR_NONE);
649: }
650: return(*((ulong*)host->h_addr_list[0]));
651: }
652:
653:
654: static void pop3_thread(void* arg)
655: {
656: char* p;
657: char str[128];
658: char buf[512];
659: char host_name[128];
660: char host_ip[64];
661: char username[LEN_ALIAS+1];
662: char password[LEN_PASS+1];
663: char challenge[256];
664: char digest[MD5_DIGEST_SIZE];
665: char* response="";
666: char* msgtxt;
667: int i;
668: int rd;
669: BOOL activity=FALSE;
670: BOOL apop=FALSE;
671: long l;
672: ulong lines;
673: ulong lines_sent;
674: long msgs,msgnum;
675: ulong bytes;
676: SOCKET socket;
677: HOSTENT* host;
678: smb_t smb;
679: smbmsg_t msg;
680: user_t user;
681: client_t client;
682: mail_t* mail;
683: pop3_t pop3=*(pop3_t*)arg;
684:
685: SetThreadName("POP3 Thread");
686: thread_up(TRUE /* setuid */);
687:
688: free(arg);
689:
690: socket=pop3.socket;
691:
692: if(startup->options&MAIL_OPT_DEBUG_POP3)
693: lprintf(LOG_DEBUG,"%04d POP3 session thread started", socket);
694:
695: #ifdef _WIN32
696: if(startup->pop3_sound[0] && !(startup->options&MAIL_OPT_MUTE))
697: PlaySound(startup->pop3_sound, NULL, SND_ASYNC|SND_FILENAME);
698: #endif
699:
700: SAFECOPY(host_ip,inet_ntoa(pop3.client_addr.sin_addr));
701:
702: if(startup->options&MAIL_OPT_DEBUG_POP3)
703: lprintf(LOG_INFO,"%04d POP3 connection accepted from: %s port %u"
704: ,socket, host_ip, ntohs(pop3.client_addr.sin_port));
705:
706: if(startup->options&MAIL_OPT_NO_HOST_LOOKUP)
707: host=NULL;
708: else
709: host=gethostbyaddr((char *)&pop3.client_addr.sin_addr
710: ,sizeof(pop3.client_addr.sin_addr),AF_INET);
711:
712: if(host!=NULL && host->h_name!=NULL)
713: SAFECOPY(host_name,host->h_name);
714: else
715: strcpy(host_name,"<no name>");
716:
717: if(startup->options&MAIL_OPT_DEBUG_POP3
718: && !(startup->options&MAIL_OPT_NO_HOST_LOOKUP)) {
719: lprintf(LOG_INFO,"%04d POP3 Hostname: %s", socket, host_name);
720: for(i=0;host!=NULL && host->h_aliases!=NULL && host->h_aliases[i]!=NULL;i++)
721: lprintf(LOG_INFO,"%04d POP3 HostAlias: %s", socket, host->h_aliases[i]);
722: }
723:
724: if(trashcan(&scfg,host_ip,"ip")) {
725: lprintf(LOG_NOTICE,"%04d !POP3 BLOCKED CLIENT IP ADDRESS: %s"
726: ,socket, host_ip);
727: sockprintf(socket,"-ERR Access denied.");
728: mail_close_socket(socket);
729: thread_down();
730: return;
731: }
732:
733: if(trashcan(&scfg,host_name,"host")) {
734: lprintf(LOG_NOTICE,"%04d !POP3 BLOCKED CLIENT HOSTNAME: %s"
735: ,socket, host_name);
736: sockprintf(socket,"-ERR Access denied.");
737: mail_close_socket(socket);
738: thread_down();
739: return;
740: }
741:
742: active_clients++, update_clients();
743:
744: /* Initialize client display */
745: client.size=sizeof(client);
746: client.time=time(NULL);
747: SAFECOPY(client.addr,host_ip);
748: SAFECOPY(client.host,host_name);
749: client.port=ntohs(pop3.client_addr.sin_port);
750: client.protocol="POP3";
751: client.user="<unknown>";
752: client_on(socket,&client,FALSE /* update */);
753:
754: SAFEPRINTF(str,"POP3: %s", host_ip);
755: status(str);
756:
757: mail=NULL;
758:
759: do {
760: memset(&smb,0,sizeof(smb));
761: memset(&msg,0,sizeof(msg));
762: memset(&user,0,sizeof(user));
763: password[0]=0;
764:
765: srand(time(NULL) ^ (DWORD)GetCurrentThreadId()); /* seed random number generator */
766: rand(); /* throw-away first result */
767: safe_snprintf(challenge,sizeof(challenge),"<%x%x%lx%lx@%.128s>"
768: ,rand(),socket,(ulong)time(NULL),clock(),startup->host_name);
769:
770: sockprintf(socket,"+OK Synchronet POP3 Server %s-%s Ready %s"
771: ,revision,PLATFORM_DESC,challenge);
772:
773: /* Requires USER command first */
774: for(i=3;i;i--) {
775: if(!sockgetrsp(socket,NULL,buf,sizeof(buf)))
776: break;
777: if(!strnicmp(buf,"USER ",5))
778: break;
779: if(!strnicmp(buf,"APOP ",5)) {
780: apop=TRUE;
781: break;
782: }
783: sockprintf(socket,"-ERR USER or APOP command expected");
784: }
785: if(!i || buf[0]==0) /* no USER or APOP command received */
786: break;
787:
788: p=buf+5;
789: SKIP_WHITESPACE(p);
790: if(apop) {
791: if((response=strrchr(p,' '))!=NULL)
792: *(response++)=0;
793: else
794: response=p;
795: }
796: SAFECOPY(username,p);
797: if(!apop) {
798: sockprintf(socket,"+OK");
799: if(!sockgetrsp(socket,"PASS ",buf,sizeof(buf))) {
800: sockprintf(socket,"-ERR PASS command expected");
801: break;
802: }
803: p=buf+5;
804: SKIP_WHITESPACE(p);
805: SAFECOPY(password,p);
806: }
807: user.number=matchuser(&scfg,username,FALSE /*sysop_alias*/);
808: if(!user.number) {
809: if(scfg.sys_misc&SM_ECHO_PW)
810: lprintf(LOG_WARNING,"%04d !POP3 UNKNOWN USER: %s (password: %s)"
811: ,socket, username, password);
812: else
813: lprintf(LOG_WARNING,"%04d !POP3 UNKNOWN USER: %s"
814: ,socket, username);
815: sockprintf(socket,pop_err);
816: break;
817: }
818: if((i=getuserdat(&scfg, &user))!=0) {
819: lprintf(LOG_ERR,"%04d !POP3 ERROR %d getting data on user (%s)"
820: ,socket, i, username);
821: sockprintf(socket, pop_err);
822: break;
823: }
824: if(user.misc&(DELETED|INACTIVE)) {
825: lprintf(LOG_WARNING,"%04d !POP3 DELETED or INACTIVE user #%u (%s)"
826: ,socket, user.number, username);
827: sockprintf(socket, pop_err);
828: break;
829: }
830: if(apop) {
831: strlwr(user.pass); /* this is case-sensitive, so convert to lowercase */
832: strcat(challenge,user.pass);
833: MD5_calc(digest,challenge,strlen(challenge));
834: MD5_hex(str,digest);
835: if(strcmp(str,response)) {
836: lprintf(LOG_WARNING,"%04d !POP3 %s FAILED APOP authentication"
837: ,socket,username);
838: #if 0
839: lprintf(LOG_DEBUG,"%04d !POP3 digest data: %s",socket,challenge);
840: lprintf(LOG_DEBUG,"%04d !POP3 calc digest: %s",socket,str);
841: lprintf(LOG_DEBUG,"%04d !POP3 resp digest: %s",socket,response);
842: #endif
843: sockprintf(socket,pop_err);
844: break;
845: }
846: } else if(stricmp(password,user.pass)) {
847: if(scfg.sys_misc&SM_ECHO_PW)
848: lprintf(LOG_WARNING,"%04d !POP3 FAILED Password attempt for user %s: '%s' expected '%s'"
849: ,socket, username, password, user.pass);
850: else
851: lprintf(LOG_WARNING,"%04d !POP3 FAILED Password attempt for user %s"
852: ,socket, username);
853: sockprintf(socket, pop_err);
854: break;
855: }
856: putuserrec(&scfg,user.number,U_COMP,LEN_COMP,host_name);
857: putuserrec(&scfg,user.number,U_NOTE,LEN_NOTE,host_ip);
858:
859: /* Update client display */
860: client.user=user.alias;
861: client_on(socket,&client,TRUE /* update */);
862:
863: if(startup->options&MAIL_OPT_DEBUG_POP3)
864: lprintf(LOG_INFO,"%04d POP3 %s logged in %s", socket, user.alias, apop ? "via APOP":"");
865: SAFEPRINTF(str,"POP3: %s",user.alias);
866: status(str);
867:
868: sprintf(smb.file,"%smail",scfg.data_dir);
869: if(smb_islocked(&smb)) {
870: lprintf(LOG_WARNING,"%04d !POP3 MAIL BASE LOCKED: %s",socket,smb.last_error);
871: sockprintf(socket,"-ERR database locked, try again later");
872: break;
873: }
874: smb.retry_time=scfg.smb_retry_time;
875: smb.subnum=INVALID_SUB;
876: if((i=smb_open(&smb))!=SMB_SUCCESS) {
877: lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) opening %s",socket,i,smb.last_error,smb.file);
878: sockprintf(socket,"-ERR %d opening %s",i,smb.file);
879: break;
880: }
881:
882: mail=loadmail(&smb,&msgs,user.number,MAIL_YOUR,0);
883:
884: for(l=bytes=0;l<msgs;l++) {
885: msg.hdr.number=mail[l].number;
886: if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
887: lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message index"
888: ,socket, i, smb.last_error);
889: break;
890: }
891: if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS) {
892: lprintf(LOG_WARNING,"%04d !POP3 ERROR %d (%s) locking message header #%lu"
893: ,socket, i, smb.last_error, msg.hdr.number);
894: break;
895: }
896: i=smb_getmsghdr(&smb,&msg);
897: smb_unlockmsghdr(&smb,&msg);
898: if(i!=0) {
899: lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message header #%lu"
900: ,socket, i, smb.last_error, msg.hdr.number);
901: break;
902: }
903: bytes+=smb_getmsgtxtlen(&msg);
904: smb_freemsgmem(&msg);
905: }
906:
907: if(l<msgs) {
908: sockprintf(socket,"-ERR message #%d: %d (%s)"
909: ,mail[l].number,i,smb.last_error);
910: break;
911: }
912:
913: sockprintf(socket,"+OK %lu messages (%lu bytes)",msgs,bytes);
914:
915: while(1) { /* TRANSACTION STATE */
916: rd = sockreadline(socket, buf, sizeof(buf));
917: if(rd<0)
918: break;
919: truncsp(buf);
920: if(startup->options&MAIL_OPT_DEBUG_POP3)
921: lprintf(LOG_DEBUG,"%04d POP3 RX: %s", socket, buf);
922: if(!stricmp(buf, "NOOP")) {
923: sockprintf(socket,"+OK");
924: continue;
925: }
926: if(!stricmp(buf, "QUIT")) {
927: sockprintf(socket,"+OK");
928: break;
929: }
930: if(!stricmp(buf, "STAT")) {
931: sockprintf(socket,"+OK %lu %lu",msgs,bytes);
932: continue;
933: }
934: if(!stricmp(buf, "RSET")) {
935: if((i=smb_locksmbhdr(&smb))!=SMB_SUCCESS) {
936: lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) locking message base"
937: ,socket, i, smb.last_error);
938: sockprintf(socket,"-ERR %d locking message base",i);
939: continue;
940: }
941: for(l=0;l<msgs;l++) {
942: msg.hdr.number=mail[l].number;
943: if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
944: lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message index"
945: ,socket, i, smb.last_error);
946: break;
947: }
948: if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS) {
949: lprintf(LOG_WARNING,"%04d !POP3 ERROR %d (%s) locking message header #%lu"
950: ,socket, i, smb.last_error, msg.hdr.number);
951: break;
952: }
953: if((i=smb_getmsghdr(&smb,&msg))!=SMB_SUCCESS) {
954: smb_unlockmsghdr(&smb,&msg);
955: lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message header #%lu"
956: ,socket, i, smb.last_error, msg.hdr.number);
957: break;
958: }
959: msg.hdr.attr=mail[l].attr;
960: if((i=smb_putmsg(&smb,&msg))!=SMB_SUCCESS)
961: lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) updating message index"
962: ,socket, i, smb.last_error);
963: smb_unlockmsghdr(&smb,&msg);
964: smb_freemsgmem(&msg);
965: }
966: smb_unlocksmbhdr(&smb);
967:
968: if(l<msgs)
969: sockprintf(socket,"-ERR %d messages reset (ERROR: %d)",l,i);
970: else
971: sockprintf(socket,"+OK %lu messages (%lu bytes)",msgs,bytes);
972: continue;
973: }
974: if(!strnicmp(buf, "LIST",4) || !strnicmp(buf,"UIDL",4)) {
975: p=buf+4;
976: SKIP_WHITESPACE(p);
977: if(isdigit(*p)) {
978: msgnum=atol(p);
979: if(msgnum<1 || msgnum>msgs) {
980: lprintf(LOG_WARNING,"%04d !POP3 INVALID message #%ld"
981: ,socket, msgnum);
982: sockprintf(socket,"-ERR no such message");
983: continue;
984: }
985: msg.hdr.number=mail[msgnum-1].number;
986: if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
987: lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message index"
988: ,socket, i, smb.last_error);
989: sockprintf(socket,"-ERR %d getting message index",i);
990: break;
991: }
992: if(msg.idx.attr&MSG_DELETE) {
993: lprintf(LOG_WARNING,"%04d !POP3 ATTEMPT to list DELETED message"
994: ,socket);
995: sockprintf(socket,"-ERR message deleted");
996: continue;
997: }
998: if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS) {
999: lprintf(LOG_WARNING,"%04d !POP3 ERROR %d (%s) locking message header #%lu"
1000: ,socket, i, smb.last_error, msg.hdr.number);
1001: sockprintf(socket,"-ERR %d locking message header",i);
1002: continue;
1003: }
1004: i=smb_getmsghdr(&smb,&msg);
1005: smb_unlockmsghdr(&smb,&msg);
1006: if(i!=0) {
1007: smb_freemsgmem(&msg);
1008: lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message header #%lu"
1009: ,socket, i, smb.last_error, msg.hdr.number);
1010: sockprintf(socket,"-ERR %d getting message header",i);
1011: continue;
1012: }
1013: if(!strnicmp(buf, "LIST",4)) {
1014: sockprintf(socket,"+OK %lu %lu",msgnum,smb_getmsgtxtlen(&msg));
1015: } else /* UIDL */
1016: sockprintf(socket,"+OK %lu %lu",msgnum,msg.hdr.number);
1017:
1018: smb_freemsgmem(&msg);
1019: continue;
1020: }
1021: /* List ALL messages */
1022: sockprintf(socket,"+OK %lu messages (%lu bytes)",msgs,bytes);
1023: for(l=0;l<msgs;l++) {
1024: msg.hdr.number=mail[l].number;
1025: if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
1026: lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message index"
1027: ,socket, i, smb.last_error);
1028: break;
1029: }
1030: if(msg.idx.attr&MSG_DELETE)
1031: continue;
1032: if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS) {
1033: lprintf(LOG_WARNING,"%04d !POP3 ERROR %d (%s) locking message header #%lu"
1034: ,socket, i, smb.last_error, msg.hdr.number);
1035: break;
1036: }
1037: i=smb_getmsghdr(&smb,&msg);
1038: smb_unlockmsghdr(&smb,&msg);
1039: if(i!=0) {
1040: smb_freemsgmem(&msg);
1041: lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message header #%lu"
1042: ,socket, i, smb.last_error, msg.hdr.number);
1043: break;
1044: }
1045: if(!strnicmp(buf, "LIST",4)) {
1046: sockprintf(socket,"%lu %lu",l+1,smb_getmsgtxtlen(&msg));
1047: } else /* UIDL */
1048: sockprintf(socket,"%lu %lu",l+1,msg.hdr.number);
1049:
1050: smb_freemsgmem(&msg);
1051: }
1052: sockprintf(socket,".");
1053: continue;
1054: }
1055: activity=TRUE;
1056: if(!strnicmp(buf, "RETR ",5) || !strnicmp(buf,"TOP ",4)) {
1057: SAFEPRINTF(str,"POP3: %s", user.alias);
1058: status(str);
1059:
1060: lines=-1;
1061: p=buf+4;
1062: SKIP_WHITESPACE(p);
1063: msgnum=atol(p);
1064:
1065: if(!strnicmp(buf,"TOP ",4)) {
1066: SKIP_DIGIT(p);
1067: SKIP_WHITESPACE(p);
1068: lines=atol(p);
1069: }
1070: if(msgnum<1 || msgnum>msgs) {
1071: lprintf(LOG_WARNING,"%04d !POP3 %s ATTEMPTED to retrieve an INVALID message #%ld"
1072: ,socket, user.alias, msgnum);
1073: sockprintf(socket,"-ERR no such message");
1074: continue;
1075: }
1076: msg.hdr.number=mail[msgnum-1].number;
1077:
1078: lprintf(LOG_INFO,"%04d POP3 %s retrieving message #%ld"
1079: ,socket, user.alias, msg.hdr.number);
1080:
1081: if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
1082: lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message index"
1083: ,socket, i, smb.last_error);
1084: sockprintf(socket,"-ERR %d getting message index",i);
1085: continue;
1086: }
1087: if(msg.idx.attr&MSG_DELETE) {
1088: lprintf(LOG_WARNING,"%04d !POP3 ATTEMPT to retrieve DELETED message"
1089: ,socket);
1090: sockprintf(socket,"-ERR message deleted");
1091: continue;
1092: }
1093: if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS) {
1094: lprintf(LOG_WARNING,"%04d !POP3 ERROR %d (%s) locking message header #%lu"
1095: ,socket, i, smb.last_error, msg.hdr.number);
1096: sockprintf(socket,"-ERR %d locking message header",i);
1097: continue;
1098: }
1099: i=smb_getmsghdr(&smb,&msg);
1100: smb_unlockmsghdr(&smb,&msg);
1101: if(i!=0) {
1102: lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message header #%lu"
1103: ,socket, i, smb.last_error, msg.hdr.number);
1104: sockprintf(socket,"-ERR %d getting message header",i);
1105: continue;
1106: }
1107:
1108: if((msgtxt=smb_getmsgtxt(&smb,&msg,GETMSGTXT_ALL))==NULL) {
1109: smb_freemsgmem(&msg);
1110: lprintf(LOG_ERR,"%04d !POP3 ERROR (%s) retrieving message %lu text"
1111: ,socket, smb.last_error, msg.hdr.number);
1112: sockprintf(socket,"-ERR retrieving message text");
1113: continue;
1114: }
1115:
1116: sockprintf(socket,"+OK message follows");
1117: lprintf(LOG_DEBUG,"%04d POP3 sending message text (%u bytes)"
1118: ,socket,strlen(msgtxt));
1119: lines_sent=sockmsgtxt(socket,&msg,msgtxt,lines);
1120: /* if(startup->options&MAIL_OPT_DEBUG_POP3) */
1121: if(lines!=-1 && lines_sent<lines) /* could send *more* lines */
1122: lprintf(LOG_ERR,"%04d !POP3 ERROR sending message text (sent %ld of %ld lines)"
1123: ,socket,lines_sent,lines);
1124: else {
1125: lprintf(LOG_DEBUG,"%04d POP3 message transfer complete (%lu lines)"
1126: ,socket,lines_sent);
1127:
1128: if((i=smb_locksmbhdr(&smb))!=SMB_SUCCESS) {
1129: lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) locking message base"
1130: ,socket, i, smb.last_error);
1131: } else {
1132: if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
1133: lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message index"
1134: ,socket, i, smb.last_error);
1135: } else {
1136: msg.hdr.attr|=MSG_READ;
1137: msg.hdr.netattr|=MSG_SENT;
1138:
1139: if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS)
1140: lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) locking message header #%lu"
1141: ,socket, i, smb.last_error, msg.hdr.number);
1142: if((i=smb_putmsg(&smb,&msg))!=SMB_SUCCESS)
1143: lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) marking message #%lu as read"
1144: ,socket, i, smb.last_error, msg.hdr.number);
1145: smb_unlockmsghdr(&smb,&msg);
1146: }
1147: smb_unlocksmbhdr(&smb);
1148: }
1149: }
1150: smb_freemsgmem(&msg);
1151: smb_freemsgtxt(msgtxt);
1152: continue;
1153: }
1154: if(!strnicmp(buf, "DELE ",5)) {
1155: p=buf+5;
1156: SKIP_WHITESPACE(p);
1157: msgnum=atol(p);
1158:
1159: if(msgnum<1 || msgnum>msgs) {
1160: lprintf(LOG_WARNING,"%04d !POP3 %s ATTEMPTED to delete an INVALID message #%ld"
1161: ,socket, user.alias, msgnum);
1162: sockprintf(socket,"-ERR no such message");
1163: continue;
1164: }
1165: msg.hdr.number=mail[msgnum-1].number;
1166:
1167: lprintf(LOG_INFO,"%04d POP3 %s deleting message #%ld"
1168: ,socket, user.alias, msg.hdr.number);
1169:
1170: if((i=smb_locksmbhdr(&smb))!=SMB_SUCCESS) {
1171: lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) locking message base"
1172: ,socket, i, smb.last_error);
1173: sockprintf(socket,"-ERR %d locking message base",i);
1174: continue;
1175: }
1176: if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
1177: smb_unlocksmbhdr(&smb);
1178: lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message index"
1179: ,socket, i, smb.last_error);
1180: sockprintf(socket,"-ERR %d getting message index",i);
1181: continue;
1182: }
1183: if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS) {
1184: smb_unlocksmbhdr(&smb);
1185: lprintf(LOG_WARNING,"%04d !POP3 ERROR %d (%s) locking message header #%lu"
1186: ,socket, i, smb.last_error, msg.hdr.number);
1187: sockprintf(socket,"-ERR %d locking message header",i);
1188: continue;
1189: }
1190: if((i=smb_getmsghdr(&smb,&msg))!=SMB_SUCCESS) {
1191: smb_unlockmsghdr(&smb,&msg);
1192: smb_unlocksmbhdr(&smb);
1193: lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message header #%lu"
1194: ,socket, i, smb.last_error, msg.hdr.number);
1195: sockprintf(socket,"-ERR %d getting message header",i);
1196: continue;
1197: }
1198: msg.hdr.attr|=MSG_DELETE;
1199:
1200: if((i=smb_putmsg(&smb,&msg))==SMB_SUCCESS && msg.hdr.auxattr&MSG_FILEATTACH)
1201: delfattach(&scfg,&msg);
1202: smb_unlockmsghdr(&smb,&msg);
1203: smb_unlocksmbhdr(&smb);
1204: smb_freemsgmem(&msg);
1205: if(i!=SMB_SUCCESS) {
1206: lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) marking message as read"
1207: , socket, i, smb.last_error);
1208: sockprintf(socket,"-ERR %d marking message for deletion",i);
1209: continue;
1210: }
1211: sockprintf(socket,"+OK");
1212: if(startup->options&MAIL_OPT_DEBUG_POP3)
1213: lprintf(LOG_INFO,"%04d POP3 message deleted", socket);
1214: continue;
1215: }
1216: lprintf(LOG_WARNING,"%04d !POP3 UNSUPPORTED COMMAND from %s: '%s'"
1217: ,socket, user.alias, buf);
1218: sockprintf(socket,"-ERR UNSUPPORTED COMMAND: %s",buf);
1219: }
1220: if(user.number)
1221: logoutuserdat(&scfg,&user,time(NULL),client.time);
1222:
1223: } while(0);
1224:
1225: if(activity)
1226: lprintf(LOG_INFO,"%04d POP3 %s logged out from port %u on %s [%s]"
1227: ,socket, user.alias, ntohs(pop3.client_addr.sin_port), host_name, host_ip);
1228:
1229: status(STATUS_WFC);
1230:
1231: /* Free up resources here */
1232: if(mail!=NULL)
1233: freemail(mail);
1234:
1235: smb_freemsgmem(&msg);
1236: smb_close(&smb);
1237:
1238: if(active_clients)
1239: active_clients--, update_clients();
1240: client_off(socket);
1241:
1242: thread_down();
1243: if(startup->options&MAIL_OPT_DEBUG_POP3)
1244: lprintf(LOG_DEBUG,"%04d POP3 session thread terminated (%u threads remain, %lu clients served)"
1245: ,socket, thread_count, served);
1246:
1247: /* Must be last */
1248: mail_close_socket(socket);
1249: }
1250:
1251: static ulong rblchk(SOCKET sock, DWORD mail_addr_n, const char* rbl_addr)
1252: {
1253: char name[256];
1254: DWORD mail_addr;
1255: HOSTENT* host;
1256: struct in_addr dnsbl_result;
1257:
1258: mail_addr=ntohl(mail_addr_n);
1259: safe_snprintf(name,sizeof(name),"%ld.%ld.%ld.%ld.%.128s"
1260: ,mail_addr&0xff
1261: ,(mail_addr>>8)&0xff
1262: ,(mail_addr>>16)&0xff
1263: ,(mail_addr>>24)&0xff
1264: ,rbl_addr
1265: );
1266:
1267: if(startup->options&MAIL_OPT_DNSBL_DEBUG)
1268: lprintf(LOG_DEBUG,"%04d SMTP DNSBL Query: %s",sock,name);
1269:
1270: if((host=gethostbyname(name))==NULL)
1271: return(0);
1272:
1273: dnsbl_result.s_addr = *((ulong*)host->h_addr_list[0]);
1274: lprintf(LOG_INFO,"%04d SMTP DNSBL Query: %s resolved to: %s"
1275: ,sock,name,inet_ntoa(dnsbl_result));
1276:
1277: return(dnsbl_result.s_addr);
1278: }
1279:
1280: static ulong dns_blacklisted(SOCKET sock, IN_ADDR addr, char* host_name, char* list, char* dnsbl_ip)
1281: {
1282: char fname[MAX_PATH+1];
1283: char str[256];
1284: char* p;
1285: char* tp;
1286: FILE* fp;
1287: ulong found=0;
1288:
1289: sprintf(fname,"%sdnsbl_exempt.cfg",scfg.ctrl_dir);
1290: if(findstr(inet_ntoa(addr),fname))
1291: return(FALSE);
1292: if(findstr(host_name,fname))
1293: return(FALSE);
1294:
1295: sprintf(fname,"%sdns_blacklist.cfg", scfg.ctrl_dir);
1296: if((fp=fopen(fname,"r"))==NULL)
1297: return(FALSE);
1298:
1299: while(!feof(fp) && !found) {
1300: if(fgets(str,sizeof(str),fp)==NULL)
1301: break;
1302: truncsp(str);
1303:
1304: p=str;
1305: SKIP_WHITESPACE(p);
1306: if(*p==';' || *p==0) /* comment or blank line */
1307: continue;
1308:
1309: sprintf(list,"%.100s",p);
1310:
1311: /* terminate */
1312: tp = p;
1313: FIND_WHITESPACE(tp);
1314: *tp=0;
1315:
1316: found = rblchk(sock, addr.s_addr, p);
1317: }
1318: fclose(fp);
1319: if(found)
1320: strcpy(dnsbl_ip, inet_ntoa(addr));
1321:
1322: return(found);
1323: }
1324:
1325:
1326: static BOOL chk_email_addr(SOCKET socket, char* p, char* host_name, char* host_ip
1327: ,char* to, char* from, char* source)
1328: {
1329: char addr[64];
1330: char tmp[128];
1331:
1332: SKIP_WHITESPACE(p);
1333: if(*p=='<') p++; /* Skip '<' */
1334: SAFECOPY(addr,p);
1335: truncstr(addr,">( ");
1336:
1337: if(!trashcan(&scfg,addr,"email"))
1338: return(TRUE);
1339:
1340: lprintf(LOG_NOTICE,"%04d !SMTP BLOCKED %s e-mail address: %s"
1341: ,socket, source, addr);
1342: SAFEPRINTF2(tmp,"Blocked %s e-mail address: %s", source, addr);
1343: spamlog(&scfg, "SMTP", "REFUSED", tmp, host_name, host_ip, to, from);
1344:
1345: return(FALSE);
1346: }
1347:
1348: static void signal_smtp_sem(void)
1349: {
1350: int file;
1351:
1352: if(scfg.smtpmail_sem[0]==0)
1353: return; /* do nothing */
1354:
1355: if((file=open(scfg.smtpmail_sem,O_WRONLY|O_CREAT|O_TRUNC,S_IREAD|S_IWRITE))!=-1)
1356: close(file);
1357: }
1358:
1359: /*****************************************************************************/
1360: /* Returns command line generated from instr with %c replacments */
1361: /*****************************************************************************/
1362: static char* mailcmdstr(char* instr, char* msgpath, char* lstpath, char* errpath
1363: ,char* host, char* ip, uint usernum
1364: ,char* sender, char* sender_addr, char* reverse_path, char* cmd)
1365: {
1366: char str[1024];
1367: int i,j,len;
1368:
1369: len=strlen(instr);
1370: for(i=j=0;i<len;i++) {
1371: if(instr[i]=='%') {
1372: i++;
1373: cmd[j]=0;
1374: switch(toupper(instr[i])) {
1375: case 'E':
1376: strcat(cmd,errpath);
1377: break;
1378: case 'H':
1379: strcat(cmd,host);
1380: break;
1381: case 'I':
1382: strcat(cmd,ip);
1383: break;
1384: case 'G': /* Temp directory */
1385: strcat(cmd,scfg.temp_dir);
1386: break;
1387: case 'J':
1388: strcat(cmd,scfg.data_dir);
1389: break;
1390: case 'K':
1391: strcat(cmd,scfg.ctrl_dir);
1392: break;
1393: case 'L':
1394: strcat(cmd,lstpath);
1395: break;
1396: case 'F':
1397: case 'M':
1398: strcat(cmd,msgpath);
1399: break;
1400: case 'O': /* SysOp */
1401: strcat(cmd,scfg.sys_op);
1402: break;
1403: case 'Q': /* QWK ID */
1404: strcat(cmd,scfg.sys_id);
1405: break;
1406: case 'R': /* reverse path */
1407: strcat(cmd,reverse_path);
1408: break;
1409: case 'S': /* sender name */
1410: strcat(cmd,sender);
1411: break;
1412: case 'A': /* sender address */
1413: strcat(cmd,sender_addr);
1414: break;
1415: case 'V': /* Synchronet Version */
1416: sprintf(str,"%s%c",VERSION,REVISION);
1417: strcat(cmd,str);
1418: break;
1419: case 'Z':
1420: strcat(cmd,scfg.text_dir);
1421: break;
1422: case '!': /* EXEC Directory */
1423: strcat(cmd,scfg.exec_dir);
1424: break;
1425: case '@': /* EXEC Directory for DOS/OS2/Win32, blank for Unix */
1426: #ifndef __unix__
1427: strcat(cmd,scfg.exec_dir);
1428: #endif
1429: break;
1430: case '%': /* %% for percent sign */
1431: strcat(cmd,"%");
1432: break;
1433: case '?': /* Platform */
1434: #ifdef __OS2__
1435: SAFECOPY(str,"OS2");
1436: #else
1437: SAFECOPY(str,PLATFORM_DESC);
1438: #endif
1439: strlwr(str);
1440: strcat(cmd,str);
1441: break;
1442: case 'U': /* User number */
1443: sprintf(str,"%u",usernum);
1444: strcat(cmd,str);
1445: break;
1446: default: /* unknown specification */
1447: break;
1448: }
1449: j=strlen(cmd);
1450: }
1451: else
1452: cmd[j++]=instr[i];
1453: }
1454: cmd[j]=0;
1455:
1456: return(cmd);
1457: }
1458: #ifdef JAVASCRIPT
1459:
1460: static void
1461: js_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
1462: {
1463: char line[64];
1464: char file[MAX_PATH+1];
1465: char* warning;
1466: SOCKET* sock;
1467:
1468: if((sock=(SOCKET*)JS_GetContextPrivate(cx))==NULL)
1469: return;
1470:
1471: if(report==NULL) {
1472: lprintf(LOG_ERR,"!JavaScript: %s", message);
1473: return;
1474: }
1475:
1476: if(report->filename)
1477: SAFEPRINTF(file," %s",report->filename);
1478: else
1479: file[0]=0;
1480:
1481: if(report->lineno)
1482: SAFEPRINTF(line," line %u",report->lineno);
1483: else
1484: line[0]=0;
1485:
1486: if(JSREPORT_IS_WARNING(report->flags)) {
1487: if(JSREPORT_IS_STRICT(report->flags))
1488: warning="strict warning";
1489: else
1490: warning="warning";
1491: } else
1492: warning="";
1493:
1494: lprintf(LOG_ERR,"%04d !JavaScript %s%s%s: %s"
1495: ,*sock, warning ,file, line, message);
1496: }
1497:
1498: static JSBool
1499: js_log(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1500: {
1501: uintN i=0;
1502: int32 level=LOG_INFO;
1503: JSString* str=NULL;
1504: SOCKET* sock;
1505:
1506: if((sock=(SOCKET*)JS_GetContextPrivate(cx))==NULL)
1507: return(JS_FALSE);
1508:
1509: if(JSVAL_IS_NUMBER(argv[i]))
1510: JS_ValueToInt32(cx,argv[i++],&level);
1511:
1512: for(; i<argc; i++) {
1513: if((str=JS_ValueToString(cx, argv[i]))==NULL)
1514: return(JS_FALSE);
1515: lprintf(level,"%04d JavaScript: %s",*sock,JS_GetStringBytes(str));
1516: }
1517:
1518: if(str==NULL)
1519: *rval = JSVAL_VOID;
1520: else
1521: *rval = STRING_TO_JSVAL(str);
1522:
1523: return(JS_TRUE);
1524: }
1525:
1526: static JSFunctionSpec js_global_functions[] = {
1527: {"write", js_log, 0},
1528: {"writeln", js_log, 0},
1529: {"print", js_log, 0},
1530: {"log", js_log, 0},
1531: {0}
1532: };
1533:
1534: static BOOL
1535: js_mailproc(SOCKET sock, client_t* client, user_t* user
1536: ,char* cmdline
1537: ,char* msgtxt_fname, char* rcptlst_fname, char* proc_err_fname
1538: ,char* sender, char* sender_addr, char* reverse_path)
1539: {
1540: char* p;
1541: char fname[MAX_PATH+1];
1542: char path[MAX_PATH+1];
1543: char arg[MAX_PATH+1];
1544: BOOL success=FALSE;
1545: JSRuntime* js_runtime=NULL;
1546: JSContext* js_cx=NULL;
1547: JSObject* js_glob;
1548: JSObject* argv;
1549: jsuint argc;
1550: JSScript* js_script;
1551: js_branch_t js_branch;
1552: jsval val;
1553: jsval rval=JSVAL_VOID;
1554:
1555: ZERO_VAR(js_branch);
1556:
1557: SAFECOPY(fname,cmdline);
1558: truncstr(fname," \t");
1559: if(getfext(fname)==NULL) /* No extension specified, assume '.js' */
1560: strcat(fname,".js");
1561:
1562: SAFECOPY(path,fname);
1563: if(getfname(path)==path) /* No path specified, assume exec_dir */
1564: sprintf(path,"%s%s",scfg.exec_dir,fname);
1565:
1566: do {
1567:
1568: lprintf(LOG_DEBUG,"%04d JavaScript: Creating runtime: %lu bytes\n"
1569: ,sock, startup->js.max_bytes);
1570:
1571: if((js_runtime = JS_NewRuntime(startup->js.max_bytes))==NULL)
1572: break;
1573:
1574: lprintf(LOG_DEBUG,"%04d JavaScript: Initializing context (stack: %lu bytes)\n"
1575: ,sock, startup->js.cx_stack);
1576:
1577: if((js_cx = JS_NewContext(js_runtime, startup->js.cx_stack))==NULL)
1578: break;
1579:
1580: JS_SetErrorReporter(js_cx, js_ErrorReporter);
1581:
1582: JS_SetContextPrivate(js_cx, &sock);
1583:
1584: /* Global Object */
1585: if((js_glob=js_CreateGlobalObject(js_cx, &scfg, NULL))==NULL)
1586: break;
1587:
1588: if (!JS_DefineFunctions(js_cx, js_glob, js_global_functions))
1589: break;
1590:
1591: /* Internal JS Object */
1592: if(js_CreateInternalJsObject(js_cx, js_glob, &js_branch)==NULL)
1593: break;
1594:
1595: /* Client Object */
1596: if(js_CreateClientObject(js_cx, js_glob, "client", client, sock)==NULL)
1597: break;
1598:
1599: /* System Object */
1600: if(js_CreateSystemObject(js_cx, js_glob, &scfg, uptime, startup->host_name, SOCKLIB_DESC)==NULL)
1601: break;
1602:
1603: /* Socket Class */
1604: if(js_CreateSocketClass(js_cx, js_glob)==NULL)
1605: break;
1606:
1607: /* MsgBase Class */
1608: if(js_CreateMsgBaseClass(js_cx, js_glob, &scfg)==NULL)
1609: break;
1610:
1611: /* File Class */
1612: if(js_CreateFileClass(js_cx, js_glob)==NULL)
1613: break;
1614:
1615: /* User class */
1616: if(js_CreateUserClass(js_cx, js_glob, &scfg)==NULL)
1617: break;
1618:
1619: /* Area and "user" Objects */
1620: if(!js_CreateUserObjects(js_cx, js_glob, &scfg, user, NULL, NULL))
1621: break;
1622:
1623: /* Convert command-line to argv/argc */
1624: argv=JS_NewArrayObject(js_cx, 0, NULL);
1625: JS_DefineProperty(js_cx, js_glob, "argv", OBJECT_TO_JSVAL(argv)
1626: ,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE);
1627:
1628: p=cmdline;
1629: FIND_WHITESPACE(p);
1630: SKIP_WHITESPACE(p);
1631: for(argc=0;*p;argc++) {
1632: SAFECOPY(arg,p);
1633: truncstr(arg," \t");
1634: val=STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx,arg));
1635: if(!JS_SetElement(js_cx, argv, argc, &val))
1636: break;
1637: FIND_WHITESPACE(p);
1638: SKIP_WHITESPACE(p);
1639: }
1640: JS_DefineProperty(js_cx, js_glob, "argc", INT_TO_JSVAL(argc)
1641: ,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE);
1642:
1643: /* Mailproc "API" filenames */
1644: JS_DefineProperty(js_cx, js_glob, "message_text_filename"
1645: ,STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx,msgtxt_fname))
1646: ,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
1647:
1648: JS_DefineProperty(js_cx, js_glob, "recipient_list_filename"
1649: ,STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx,rcptlst_fname))
1650: ,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
1651:
1652: JS_DefineProperty(js_cx, js_glob, "processing_error_filename"
1653: ,STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx,proc_err_fname))
1654: ,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
1655:
1656: JS_DefineProperty(js_cx, js_glob, "sender_name"
1657: ,STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx,sender))
1658: ,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
1659:
1660: JS_DefineProperty(js_cx, js_glob, "sender_address"
1661: ,STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx,sender_addr))
1662: ,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
1663:
1664: JS_DefineProperty(js_cx, js_glob, "reverse_path"
1665: ,STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx,reverse_path))
1666: ,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
1667:
1668: if((js_script=JS_CompileFile(js_cx, js_glob, path))==NULL)
1669: break;
1670:
1671: success=JS_ExecuteScript(js_cx, js_glob, js_script, &rval);
1672:
1673: js_EvalOnExit(js_cx, js_glob, &js_branch);
1674:
1675: } while(0);
1676:
1677: if(js_cx!=NULL)
1678: JS_DestroyContext(js_cx);
1679: if(js_runtime!=NULL)
1680: JS_DestroyRuntime(js_runtime);
1681:
1682: return(success);
1683: }
1684: #endif
1685:
1686:
1687: static int parse_header_field(uchar* buf, smbmsg_t* msg, ushort* type)
1688: {
1689: char* p;
1690: char field[128];
1691: int len;
1692: ushort nettype;
1693:
1694: if(buf[0]<=' ' && *type!=UNKNOWN) { /* folded header, append to previous */
1695: p=buf;
1696: truncsp(p);
1697: smb_hfield_append_str(msg,*type,"\r\n");
1698: return smb_hfield_append_str(msg, *type, p);
1699: }
1700:
1701: if((p=strchr(buf,':'))==NULL)
1702: return smb_hfield_str(msg, *type=RFC822HEADER, buf);
1703:
1704: len=(ulong)p-(ulong)buf;
1705: if(len>sizeof(field)-1)
1706: len=sizeof(field)-1;
1707: sprintf(field,"%.*s",len,buf);
1708: truncsp(field);
1709:
1710: p++; /* skip colon */
1711: SKIP_WHITESPACE(p);
1712: truncsp(p);
1713:
1714: if(!stricmp(field, "TO"))
1715: return smb_hfield_str(msg, *type=RFC822TO, p);
1716:
1717: if(!stricmp(field, "REPLY-TO")) {
1718: smb_hfield_str(msg, *type=RFC822REPLYTO, p);
1719: if(*p=='<') {
1720: p++;
1721: truncstr(p,">");
1722: }
1723: nettype=NET_INTERNET;
1724: smb_hfield(msg, REPLYTONETTYPE, sizeof(nettype), &nettype);
1725: return smb_hfield_str(msg, *type=REPLYTONETADDR, p);
1726: }
1727: if(!stricmp(field, "FROM"))
1728: return smb_hfield_str(msg, *type=RFC822FROM, p);
1729:
1730: if(!stricmp(field, "ORGANIZATION"))
1731: return smb_hfield_str(msg, *type=SENDERORG, p);
1732:
1733: if(!stricmp(field, "DATE")) {
1734: msg->hdr.when_written=rfc822date(p);
1735: *type=UNKNOWN;
1736: return(0);
1737: }
1738: if(!stricmp(field, "MESSAGE-ID"))
1739: return smb_hfield_str(msg, *type=RFC822MSGID, p);
1740:
1741: if(!stricmp(field, "IN-REPLY-TO"))
1742: return smb_hfield_str(msg, *type=RFC822REPLYID, p);
1743:
1744: /* Fall-through */
1745: return smb_hfield_str(msg, *type=RFC822HEADER, buf);
1746: }
1747:
1748: static int chk_received_hdr(SOCKET socket,const char *buf,IN_ADDR *dnsbl_result, char *dnsbl, char *dnsbl_ip)
1749: {
1750: char host_name[128];
1751: IN_ADDR check_addr;
1752: char *fromstr;
1753: char ip[16];
1754: char *p;
1755: char *p2;
1756: char *last;
1757:
1758: fromstr=(char *)malloc(strlen(buf)+1);
1759: if(fromstr==NULL)
1760: return(0);
1761: strcpy(fromstr,buf);
1762: strlwr(fromstr);
1763: do {
1764: p=strstr(fromstr,"from ");
1765: if(p==NULL)
1766: break;
1767: p+=4;
1768: SKIP_WHITESPACE(p);
1769: if(*p==0)
1770: break;
1771: p2=host_name;
1772: for(;*p && !isspace(*p) && p2<host_name+126;p++) {
1773: *p2++=*p;
1774: }
1775: *p2=0;
1776: p=strtok_r(fromstr,"[",&last);
1777: if(p==NULL)
1778: break;
1779: p=strtok_r(NULL,"]",&last);
1780: if(p==NULL)
1781: break;
1782: strncpy(ip,p,16);
1783: ip[15]=0;
1784: check_addr.s_addr = inet_addr(ip);
1785: if(startup->options&MAIL_OPT_DNSBL_DEBUG)
1786: lprintf(LOG_DEBUG,"%04d DEBUG checking %s (%s)",socket,host_name,ip);
1787: if((dnsbl_result->s_addr=dns_blacklisted(socket,check_addr,host_name,dnsbl,dnsbl_ip))!=0)
1788: lprintf(LOG_WARNING,"%04d !SMTP BLACKLISTED SERVER on %s: %s [%s] = %s"
1789: ,socket, dnsbl, host_name, ip, inet_ntoa(*dnsbl_result));
1790: } while(0);
1791: free(fromstr);
1792: return(dnsbl_result->s_addr);
1793: }
1794:
1795: static void parse_mail_address(char* p
1796: ,char* name, size_t name_len
1797: ,char* addr, size_t addr_len)
1798: {
1799: char* tp;
1800: char tmp[128];
1801:
1802: SKIP_WHITESPACE(p);
1803:
1804: /* Get the address */
1805: if((tp=strchr(p,'<'))!=NULL)
1806: tp++;
1807: else
1808: tp=p;
1809: SKIP_WHITESPACE(tp);
1810: sprintf(addr,"%.*s",addr_len,tp);
1811: truncstr(addr,">( ");
1812:
1813: SAFECOPY(tmp,p);
1814: p=tmp;
1815: /* Get the "name" (if possible) */
1816: if((tp=strchr(p,'('))!=NULL) { /* name in parenthesis? */
1817: p=tp+1;
1818: tp=strchr(p,')');
1819: } else if((tp=strchr(p,'"'))!=NULL) { /* name in quotes? */
1820: p=tp+1;
1821: tp=strchr(p,'"');
1822: } else if(*p=='<') { /* address in brackets? */
1823: p++;
1824: tp=strchr(p,'>');
1825: } else /* name, then address in brackets */
1826: tp=strchr(p,'<');
1827: if(tp) *tp=0;
1828: sprintf(name,"%.*s",name_len,p);
1829: truncsp(name);
1830: }
1831:
1832: static void smtp_thread(void* arg)
1833: {
1834: int i,j;
1835: int rd;
1836: char str[512];
1837: char tmp[128];
1838: char path[MAX_PATH+1];
1839: char value[INI_MAX_VALUE_LEN];
1840: str_list_t sec_list;
1841: char* section;
1842: char buf[1024],*p,*tp,*cp;
1843: char hdrfield[512];
1844: char alias_buf[128];
1845: char name_alias_buf[128];
1846: char reverse_path[128];
1847: char date[64];
1848: char qwkid[32];
1849: char rcpt_name[128];
1850: char rcpt_addr[128];
1851: char sender[128];
1852: char sender_addr[128];
1853: char hello_name[128];
1854: char user_name[LEN_ALIAS+1];
1855: char user_pass[LEN_PASS+1];
1856: char relay_list[MAX_PATH+1];
1857: char domain_list[MAX_PATH+1];
1858: char spam_bait[MAX_PATH+1];
1859: char spam_block[MAX_PATH+1];
1860: char host_name[128];
1861: char host_ip[64];
1862: char dnsbl[256];
1863: char dnsbl_ip[64];
1864: char* telegram_buf;
1865: char* msgbuf;
1866: char challenge[256];
1867: char response[128];
1868: char secret[64];
1869: char md5_data[384];
1870: char digest[MD5_DIGEST_SIZE];
1871: char dest_host[128];
1872: char* errmsg;
1873: ushort dest_port;
1874: socklen_t addr_len;
1875: ushort hfield_type;
1876: ushort nettype;
1877: ushort agent;
1878: uint usernum;
1879: ulong lines=0;
1880: ulong hdr_lines=0;
1881: ulong hdr_len=0;
1882: ulong length;
1883: ulong badcmds=0;
1884: BOOL esmtp=FALSE;
1885: BOOL telegram=FALSE;
1886: BOOL forward=FALSE;
1887: BOOL no_forward=FALSE;
1888: BOOL auth_login;
1889: BOOL routed=FALSE;
1890: BOOL dnsbl_recvhdr;
1891: BOOL msg_handled;
1892: uint subnum=INVALID_SUB;
1893: FILE* msgtxt=NULL;
1894: char msgtxt_fname[MAX_PATH+1];
1895: FILE* rcptlst;
1896: char rcptlst_fname[MAX_PATH+1];
1897: ushort rcpt_count=0;
1898: FILE* proc_err;
1899: char proc_err_fname[MAX_PATH+1];
1900: char session_id[MAX_PATH+1];
1901: FILE* spy=NULL;
1902: SOCKET socket;
1903: HOSTENT* host;
1904: int smb_error;
1905: smb_t smb;
1906: smbmsg_t msg;
1907: smbmsg_t newmsg;
1908: user_t user;
1909: user_t relay_user;
1910: node_t node;
1911: client_t client;
1912: smtp_t smtp=*(smtp_t*)arg;
1913: SOCKADDR_IN server_addr;
1914: IN_ADDR dnsbl_result;
1915: BOOL* mailproc_match;
1916: enum {
1917: SMTP_STATE_INITIAL
1918: ,SMTP_STATE_HELO
1919: ,SMTP_STATE_MAIL_FROM
1920: ,SMTP_STATE_RCPT_TO
1921: ,SMTP_STATE_DATA_HEADER
1922: ,SMTP_STATE_DATA_BODY
1923:
1924: } state = SMTP_STATE_INITIAL;
1925:
1926: enum {
1927: SMTP_CMD_NONE
1928: ,SMTP_CMD_MAIL
1929: ,SMTP_CMD_SEND
1930: ,SMTP_CMD_SOML
1931: ,SMTP_CMD_SAML
1932:
1933: } cmd = SMTP_CMD_NONE;
1934:
1935: SetThreadName("SMTP Thread");
1936: thread_up(TRUE /* setuid */);
1937:
1938: free(arg);
1939:
1940: socket=smtp.socket;
1941:
1942: lprintf(LOG_DEBUG,"%04d SMTP RX Session thread started", socket);
1943:
1944: #ifdef _WIN32
1945: if(startup->inbound_sound[0] && !(startup->options&MAIL_OPT_MUTE))
1946: PlaySound(startup->inbound_sound, NULL, SND_ASYNC|SND_FILENAME);
1947: #endif
1948:
1949: addr_len=sizeof(server_addr);
1950: if((i=getsockname(socket, (struct sockaddr *)&server_addr,&addr_len))!=0) {
1951: lprintf(LOG_ERR,"%04d !SMTP ERROR %d (%d) getting address/port"
1952: ,socket, i, ERROR_VALUE);
1953: sockprintf(socket,sys_error);
1954: mail_close_socket(socket);
1955: thread_down();
1956: return;
1957: }
1958:
1959: if((mailproc_match=alloca(sizeof(BOOL)*mailproc_count))==NULL) {
1960: lprintf(LOG_ERR,"%04d !SMTP ERROR allocating memory for mailproc_match", socket);
1961: sockprintf(socket,sys_error);
1962: mail_close_socket(socket);
1963: thread_down();
1964: return;
1965: }
1966: memset(mailproc_match,FALSE,sizeof(BOOL)*mailproc_count);
1967:
1968: memset(&smb,0,sizeof(smb));
1969: memset(&msg,0,sizeof(msg));
1970: memset(&user,0,sizeof(user));
1971: memset(&relay_user,0,sizeof(relay_user));
1972:
1973: SAFECOPY(host_ip,inet_ntoa(smtp.client_addr.sin_addr));
1974:
1975: lprintf(LOG_INFO,"%04d SMTP Connection accepted from: %s port %u"
1976: , socket, host_ip, ntohs(smtp.client_addr.sin_port));
1977:
1978: if(startup->options&MAIL_OPT_NO_HOST_LOOKUP)
1979: host=NULL;
1980: else
1981: host=gethostbyaddr ((char *)&smtp.client_addr.sin_addr
1982: ,sizeof(smtp.client_addr.sin_addr),AF_INET);
1983:
1984: if(host!=NULL && host->h_name!=NULL)
1985: SAFECOPY(host_name,host->h_name);
1986: else
1987: strcpy(host_name,"<no name>");
1988:
1989: if(!(startup->options&MAIL_OPT_NO_HOST_LOOKUP)) {
1990: lprintf(LOG_INFO,"%04d SMTP Hostname: %s", socket, host_name);
1991: for(i=0;host!=NULL && host->h_aliases!=NULL && host->h_aliases[i]!=NULL;i++)
1992: lprintf(LOG_INFO,"%04d SMTP HostAlias: %s", socket, host->h_aliases[i]);
1993: #if 0
1994: if(host!=NULL) {
1995: ip=resolve_ip(host_name);
1996: if(ip!=smtp.client_addr.sin_addr.s_addr) {
1997: smtp.client_addr.sin_addr.s_addr=ip;
1998: lprintf(LOG_WARNING,"%04d !SMTP DNS/IP ADDRESS MISMATCH: %s vs %s"
1999: ,socket, inet_ntoa(smtp.client_addr.sin_addr), host_ip);
2000: sockprintf(socket,"550 DNS and IP address mismatch");
2001: mail_close_socket(socket);
2002: thread_down();
2003: return;
2004: }
2005: }
2006: #endif
2007: }
2008:
2009: SAFECOPY(hello_name,host_name);
2010:
2011: sprintf(spam_bait,"%sspambait.cfg",scfg.ctrl_dir);
2012: sprintf(spam_block,"%sspamblock.cfg",scfg.ctrl_dir);
2013:
2014: if(trashcan(&scfg,host_ip,"ip") || findstr(host_ip,spam_block)) {
2015: lprintf(LOG_NOTICE,"%04d !SMTP BLOCKED SERVER IP ADDRESS: %s"
2016: ,socket, host_ip);
2017: sockprintf(socket,"550 Access denied.");
2018: mail_close_socket(socket);
2019: thread_down();
2020: return;
2021: }
2022:
2023: if(trashcan(&scfg,host_name,"host") || findstr(host_name,spam_block)) {
2024: lprintf(LOG_NOTICE,"%04d !SMTP BLOCKED SERVER HOSTNAME: %s"
2025: ,socket, host_name);
2026: sockprintf(socket,"550 Access denied.");
2027: mail_close_socket(socket);
2028: thread_down();
2029: return;
2030: }
2031:
2032: active_clients++, update_clients();
2033:
2034: /* SPAM Filters (mail-abuse.org) */
2035: dnsbl_result.s_addr = dns_blacklisted(socket,smtp.client_addr.sin_addr,host_name,dnsbl,dnsbl_ip);
2036: if(dnsbl_result.s_addr) {
2037: lprintf(LOG_WARNING,"%04d !SMTP BLACKLISTED SERVER on %s: %s [%s] = %s"
2038: ,socket, dnsbl, host_name, dnsbl_ip, inet_ntoa(dnsbl_result));
2039: if(startup->options&MAIL_OPT_DNSBL_REFUSE) {
2040: SAFEPRINTF2(str,"Listed on %s as %s", dnsbl, inet_ntoa(dnsbl_result));
2041: spamlog(&scfg, "SMTP", "SESSION REFUSED", str, host_name, dnsbl_ip, NULL, NULL);
2042: sockprintf(socket
2043: ,"550 Mail from %s refused due to listing at %s"
2044: ,dnsbl_ip, dnsbl);
2045: mail_close_socket(socket);
2046: lprintf(LOG_WARNING,"%04d !SMTP REFUSED SESSION from blacklisted server"
2047: ,socket);
2048: thread_down();
2049: if(active_clients)
2050: active_clients--, update_clients();
2051: return;
2052: }
2053: }
2054:
2055: sprintf(smb.file,"%smail",scfg.data_dir);
2056: if(smb_islocked(&smb)) {
2057: lprintf(LOG_WARNING,"%04d !SMTP MAIL BASE LOCKED: %s"
2058: ,socket, smb.last_error);
2059: sockprintf(socket,sys_unavail);
2060: mail_close_socket(socket);
2061: thread_down();
2062: if(active_clients)
2063: active_clients--, update_clients();
2064: return;
2065: }
2066:
2067: srand(time(NULL) ^ (DWORD)GetCurrentThreadId()); /* seed random number generator */
2068: rand(); /* throw-away first result */
2069: SAFEPRINTF3(session_id,"%x%x%lx",socket,rand(),clock());
2070:
2071: SAFEPRINTF2(rcptlst_fname,"%sSBBS_SMTP.%s.lst", scfg.temp_dir, session_id);
2072: rcptlst=fopen(rcptlst_fname,"w+");
2073: if(rcptlst==NULL) {
2074: lprintf(LOG_ERR,"%04d !SMTP ERROR %d creating recipient list: %s"
2075: ,socket, errno, rcptlst_fname);
2076: sockprintf(socket,sys_error);
2077: mail_close_socket(socket);
2078: thread_down();
2079: if(active_clients)
2080: active_clients--, update_clients();
2081: return;
2082: }
2083:
2084: if(trashcan(&scfg,host_name,"smtpspy")
2085: || trashcan(&scfg,host_ip,"smtpspy")) {
2086: sprintf(str,"%ssmtpspy.txt", scfg.logs_dir);
2087: spy=fopen(str,"a");
2088: }
2089:
2090: /* Initialize client display */
2091: client.size=sizeof(client);
2092: client.time=time(NULL);
2093: SAFECOPY(client.addr,host_ip);
2094: SAFECOPY(client.host,host_name);
2095: client.port=ntohs(smtp.client_addr.sin_port);
2096: client.protocol="SMTP";
2097: client.user="<unknown>";
2098: client_on(socket,&client,FALSE /* update */);
2099:
2100: SAFEPRINTF(str,"SMTP: %s",host_ip);
2101: status(str);
2102:
2103: sockprintf(socket,"220 %s Synchronet SMTP Server %s-%s Ready"
2104: ,startup->host_name,revision,PLATFORM_DESC);
2105: while(1) {
2106: rd = sockreadline(socket, buf, sizeof(buf));
2107: if(rd<0)
2108: break;
2109: truncsp(buf);
2110: if(spy!=NULL)
2111: fprintf(spy,"%s\n",buf);
2112: if(relay_user.number==0 && dnsbl_result.s_addr && startup->options&MAIL_OPT_DNSBL_THROTTLE)
2113: mswait(DNSBL_THROTTLE_VALUE);
2114: if(state>=SMTP_STATE_DATA_HEADER) {
2115: if(!strcmp(buf,".")) {
2116:
2117: state=SMTP_STATE_HELO; /* RESET state machine here in case of error */
2118: cmd=SMTP_CMD_NONE;
2119:
2120: if(msgtxt==NULL) {
2121: lprintf(LOG_ERR,"%04d !SMTP NO MESSAGE TEXT FILE POINTER?", socket);
2122: sockprintf(socket,"554 No message text");
2123: continue;
2124: }
2125:
2126: if(ftell(msgtxt)<1) {
2127: lprintf(LOG_ERR,"%04d !SMTP INVALID MESSAGE LENGTH: %ld (%lu lines)"
2128: , socket, ftell(msgtxt), lines);
2129: sockprintf(socket,"554 No message text");
2130: continue;
2131: }
2132:
2133: lprintf(LOG_INFO,"%04d SMTP End of message (body: %lu lines, %lu bytes, header: %lu lines, %lu bytes)"
2134: , socket, lines, ftell(msgtxt)-hdr_len, hdr_lines, hdr_len);
2135:
2136: /* Twit-listing (sender's name and e-mail addresses) here */
2137: sprintf(path,"%stwitlist.cfg",scfg.ctrl_dir);
2138: if(fexist(path) && (findstr(sender,path) || findstr(sender_addr,path))) {
2139: lprintf(LOG_NOTICE,"%04d !SMTP FILTERING TWIT-LISTED SENDER: %s <%s>"
2140: ,socket, sender, sender_addr);
2141: SAFEPRINTF2(tmp,"Twit-listed sender: %s <%s>", sender, sender_addr);
2142: spamlog(&scfg, "SMTP", "REFUSED", tmp, host_name, host_ip, rcpt_addr, reverse_path);
2143: sockprintf(socket, "554 Sender not allowed.");
2144: continue;
2145: }
2146:
2147: if(telegram==TRUE) { /* Telegram */
2148: const char* head="\1n\1h\1cInstant Message\1n from \1h\1y";
2149: const char* tail="\1n:\r\n\1h";
2150: rewind(msgtxt);
2151: length=filelength(fileno(msgtxt));
2152:
2153: p=strchr(sender_addr,'@');
2154: if(p==NULL || resolve_ip(p+1)!=smtp.client_addr.sin_addr.s_addr)
2155: /* Append real IP and hostname if different */
2156: safe_snprintf(str,sizeof(str),"%s%s\r\n\1w[\1n%s\1h] (\1n%s\1h)%s"
2157: ,head,sender_addr,host_ip,host_name,tail);
2158: else
2159: safe_snprintf(str,sizeof(str),"%s%s%s",head,sender_addr,tail);
2160:
2161: if((telegram_buf=(char*)malloc(length+strlen(str)+1))==NULL) {
2162: lprintf(LOG_CRIT,"%04d !SMTP ERROR allocating %lu bytes of memory for telegram from %s"
2163: ,socket,length+strlen(str)+1,sender_addr);
2164: sockprintf(socket, "452 Insufficient system storage");
2165: continue;
2166: }
2167: strcpy(telegram_buf,str); /* can't use SAFECOPY here */
2168: if(fread(telegram_buf+strlen(str),1,length,msgtxt)!=length) {
2169: lprintf(LOG_ERR,"%04d !SMTP ERROR reading %lu bytes from telegram file"
2170: ,socket,length);
2171: sockprintf(socket, "452 Insufficient system storage");
2172: free(telegram_buf);
2173: continue;
2174: }
2175: telegram_buf[length+strlen(str)]=0; /* Need ASCIIZ */
2176:
2177: /* Send telegram to users */
2178: sec_list=iniReadSectionList(rcptlst,NULL); /* Each section is a recipient */
2179: for(rcpt_count=0; sec_list!=NULL
2180: && sec_list[rcpt_count]!=NULL
2181: && rcpt_count<startup->max_recipients; rcpt_count++) {
2182:
2183: section=sec_list[rcpt_count];
2184:
2185: SAFECOPY(rcpt_name,iniReadString(rcptlst,section ,smb_hfieldtype(RECIPIENT),"unknown",value));
2186: usernum=iniReadInteger(rcptlst,section ,smb_hfieldtype(RECIPIENTEXT),0);
2187: SAFECOPY(rcpt_addr,iniReadString(rcptlst,section ,smb_hfieldtype(RECIPIENTNETADDR),rcpt_name,value));
2188:
2189: if((i=putsmsg(&scfg,usernum,telegram_buf))==0)
2190: lprintf(LOG_INFO,"%04d SMTP Created telegram (%ld/%u bytes) from %s to %s <%s>"
2191: ,socket, length, strlen(telegram_buf), sender_addr, rcpt_name, rcpt_addr);
2192: else
2193: lprintf(LOG_ERR,"%04d !SMTP ERROR %d creating telegram from %s to %s <%s>"
2194: ,socket, i, sender_addr, rcpt_name, rcpt_addr);
2195: }
2196: iniFreeStringList(sec_list);
2197: free(telegram_buf);
2198: sockprintf(socket,ok_rsp);
2199: telegram=FALSE;
2200: continue;
2201: }
2202:
2203: fclose(msgtxt), msgtxt=NULL;
2204: fclose(rcptlst), rcptlst=NULL;
2205:
2206: /* External Mail Processing here */
2207: msg_handled=FALSE;
2208: if(mailproc_count) {
2209: SAFEPRINTF2(proc_err_fname,"%sSBBS_SMTP.%s.err", scfg.temp_dir, session_id);
2210: remove(proc_err_fname);
2211:
2212: for(i=0;i<mailproc_count;i++) {
2213:
2214: /* This processor is for specific recipients only and did not match */
2215: if(strListCount(mailproc_list[i].to) && !mailproc_match[i])
2216: continue;
2217:
2218: if(!mailproc_list[i].passthru)
2219: msg_handled=TRUE;
2220:
2221: mailcmdstr(mailproc_list[i].cmdline
2222: ,msgtxt_fname, rcptlst_fname, proc_err_fname
2223: ,host_name, host_ip, relay_user.number
2224: ,sender, sender_addr, reverse_path, str);
2225: lprintf(LOG_DEBUG,"%04d SMTP Executing external process: %s"
2226: ,socket, str);
2227:
2228: if(mailproc_list[i].native) {
2229: if((j=system(str))!=0)
2230: lprintf(LOG_WARNING,"%04d !SMTP system(%s) returned %d (errno: %d)"
2231: ,socket, str, j, errno);
2232: } else /* JavaScript */
2233: js_mailproc(socket, &client, &relay_user, str /* cmdline */
2234: ,msgtxt_fname, rcptlst_fname, proc_err_fname
2235: ,sender, sender_addr, reverse_path);
2236: if(flength(proc_err_fname)>0)
2237: break;
2238: if(!fexist(msgtxt_fname) || !fexist(rcptlst_fname))
2239: break;
2240: }
2241: if(flength(proc_err_fname)>0
2242: && (proc_err=fopen(proc_err_fname,"r"))!=NULL) {
2243: while(!feof(proc_err)) {
2244: if(!fgets(str,sizeof(str),proc_err))
2245: break;
2246: truncsp(str);
2247: lprintf(LOG_WARNING,"%04d !SMTP external process error: %s", socket, str);
2248: i=atoi(str);
2249: if(i>=100 && i<1000)
2250: sockprintf(socket,"%s", str);
2251: else
2252: sockprintf(socket,"554%c%s"
2253: ,ftell(proc_err)<filelength(fileno(proc_err)) ? '-' : ' '
2254: ,str);
2255: }
2256: fclose(proc_err);
2257: msg_handled=TRUE;
2258: }
2259: else if(!fexist(msgtxt_fname) || !fexist(rcptlst_fname)) {
2260: lprintf(LOG_WARNING,"%04d SMTP External process removed %s file"
2261: ,socket, fexist(msgtxt_fname)==FALSE ? "message text" : "recipient list");
2262: sockprintf(socket,ok_rsp);
2263: msg_handled=TRUE;
2264: }
2265: else if(msg_handled)
2266: sockprintf(socket,ok_rsp);
2267: remove(proc_err_fname); /* Remove error file here */
2268: }
2269:
2270: /* Re-open files */
2271: /* We must do this before continuing for handled msgs */
2272: /* to prevent freopen(NULL) and orphaned temp files */
2273: if((rcptlst=fopen(rcptlst_fname,fexist(rcptlst_fname) ? "r":"w+"))==NULL) {
2274: lprintf(LOG_ERR,"%04d !SMTP ERROR %d re-opening recipient list: %s"
2275: ,socket, errno, rcptlst_fname);
2276: if(!msg_handled)
2277: sockprintf(socket,sys_error);
2278: continue;
2279: }
2280:
2281: if(msg_handled) {
2282: lprintf(LOG_NOTICE,"%04d SMTP Message handled by external mail processor"
2283: ,socket);
2284: continue;
2285: }
2286:
2287: if((msgtxt=fopen(msgtxt_fname,"rb"))==NULL) {
2288: lprintf(LOG_ERR,"%04d !SMTP ERROR %d re-opening message file: %s"
2289: ,socket, errno, msgtxt_fname);
2290: sockprintf(socket,sys_error);
2291: continue;
2292: }
2293:
2294: /* Initialize message header */
2295: smb_freemsgmem(&msg);
2296: memset(&msg,0,sizeof(smbmsg_t));
2297:
2298: /* Parse message header here */
2299: hfield_type=UNKNOWN;
2300: smb_error=SMB_SUCCESS; /* no SMB error */
2301: errmsg="452 Insufficient system storage";
2302: while(!feof(msgtxt)) {
2303: if(!fgets(buf,sizeof(buf),msgtxt))
2304: break;
2305: truncsp(buf);
2306: if(buf[0]==0) /* blank line marks end of header */
2307: break;
2308:
2309: if(!strnicmp(buf, "SUBJECT:",8)) {
2310: p=buf+8;
2311: SKIP_WHITESPACE(p);
2312: if(relay_user.number==0 && dnsbl_result.s_addr && startup->dnsbl_tag[0]
2313: && !(startup->options&MAIL_OPT_DNSBL_IGNORE)) {
2314: safe_snprintf(str,sizeof(str),"%.*s: %.*s"
2315: ,(int)sizeof(str)/2, startup->dnsbl_tag
2316: ,(int)sizeof(str)/2, p);
2317: p=str;
2318: lprintf(LOG_WARNING,"%04d !SMTP TAGGED MAIL SUBJECT from blacklisted server with: %s"
2319: ,socket, startup->dnsbl_tag);
2320: }
2321: smb_hfield_str(&msg, SUBJECT, p);
2322: continue;
2323: }
2324: if(!strnicmp(buf, "FROM:", 5)
2325: && !chk_email_addr(socket,buf+5,host_name,host_ip,rcpt_addr,reverse_path,"FROM")) {
2326: errmsg="554 Sender not allowed.";
2327: smb_error=SMB_FAILURE;
2328: break;
2329: }
2330: if(!strnicmp(buf, "TO:", 3)
2331: && !chk_email_addr(socket,buf+3,host_name,host_ip,rcpt_addr,reverse_path,"TO")) {
2332: errmsg="550 Unknown user.";
2333: smb_error=SMB_FAILURE;
2334: break;
2335: }
2336: if((smb_error=parse_header_field(buf,&msg,&hfield_type))!=SMB_SUCCESS) {
2337: if(smb_error==SMB_ERR_HDR_LEN)
2338: lprintf(LOG_WARNING,"%04d !SMTP MESSAGE HEADER EXCEEDS %u BYTES"
2339: ,socket, SMB_MAX_HDR_LEN);
2340: else
2341: lprintf(LOG_ERR,"%04d !SMTP ERROR %d adding header field: %s"
2342: ,socket, smb_error, buf);
2343: break;
2344: }
2345: }
2346: if(smb_error!=SMB_SUCCESS) { /* SMB Error */
2347: sockprintf(socket, errmsg);
2348: continue;
2349: }
2350: if((p=smb_get_hfield(&msg, RFC822TO, NULL))!=NULL) {
2351: if(*p=='<') p++;
2352: SAFECOPY(rcpt_name,p);
2353: truncstr(rcpt_name,">");
2354: }
2355: if((p=smb_get_hfield(&msg, RFC822FROM, NULL))!=NULL) {
2356: parse_mail_address(p
2357: ,sender ,sizeof(sender)-1
2358: ,sender_addr,sizeof(sender_addr)-1);
2359: }
2360:
2361: /* SPAM Filtering/Logging */
2362: if(relay_user.number==0 && msg.subj!=NULL && trashcan(&scfg,msg.subj,"subject")) {
2363: lprintf(LOG_WARNING,"%04d !SMTP BLOCKED SUBJECT (%s) from: %s"
2364: ,socket, msg.subj, reverse_path);
2365: SAFEPRINTF2(tmp,"Blocked subject (%s) from: %s"
2366: ,msg.subj, reverse_path);
2367: spamlog(&scfg, "SMTP", "REFUSED"
2368: ,tmp, host_name, host_ip, rcpt_addr, reverse_path);
2369: sockprintf(socket, "554 Subject not allowed.");
2370: continue;
2371: }
2372: dnsbl_recvhdr=FALSE;
2373: if(startup->options&MAIL_OPT_DNSBL_CHKRECVHDRS) {
2374: for(i=0;!dnsbl_result.s_addr && i<msg.total_hfields;i++) {
2375: if(msg.hfield[i].type == RFC822HEADER
2376: && strnicmp(msg.hfield_dat[i],"Received:",9)==0) {
2377: if(chk_received_hdr(socket,msg.hfield_dat[i],&dnsbl_result,dnsbl,dnsbl_ip)) {
2378: dnsbl_recvhdr=TRUE;
2379: break;
2380: }
2381: }
2382: }
2383: }
2384: if(relay_user.number==0 && dnsbl_result.s_addr) {
2385: if(startup->options&MAIL_OPT_DNSBL_IGNORE) {
2386: lprintf(LOG_WARNING,"%04d !SMTP IGNORED MAIL from blacklisted server"
2387: ,socket);
2388: SAFEPRINTF2(str,"Listed on %s as %s", dnsbl, inet_ntoa(dnsbl_result));
2389: spamlog(&scfg, "SMTP", "IGNORED"
2390: ,str, host_name, dnsbl_ip, rcpt_addr, reverse_path);
2391: /* pretend we received it */
2392: sockprintf(socket,ok_rsp);
2393: continue;
2394: }
2395: /* tag message as spam */
2396: if(startup->dnsbl_hdr[0]) {
2397: safe_snprintf(str,sizeof(str),"%s: %s is listed on %s as %s"
2398: ,startup->dnsbl_hdr, dnsbl_ip
2399: ,dnsbl, inet_ntoa(dnsbl_result));
2400: smb_hfield_str(&msg, RFC822HEADER, str);
2401: lprintf(LOG_WARNING,"%04d !SMTP TAGGED MAIL HEADER from blacklisted server with: %s"
2402: ,socket, startup->dnsbl_hdr);
2403: }
2404: if(startup->dnsbl_hdr[0] || startup->dnsbl_tag[0]) {
2405: SAFEPRINTF2(str,"Listed on %s as %s", dnsbl, inet_ntoa(dnsbl_result));
2406: spamlog(&scfg, "SMTP", "TAGGED", str, host_name, dnsbl_ip, rcpt_addr, reverse_path);
2407: }
2408: }
2409: if(dnsbl_recvhdr) /* DNSBL-listed IP found in Received header? */
2410: dnsbl_result.s_addr=0; /* Reset DNSBL look-up result between messages */
2411:
2412: if(sender[0]==0) {
2413: lprintf(LOG_WARNING,"%04d !SMTP MISSING mail header 'FROM' field", socket);
2414: sockprintf(socket, "554 Mail header missing 'FROM' field");
2415: subnum=INVALID_SUB;
2416: continue;
2417: }
2418: nettype=NET_INTERNET;
2419: smb_hfield_str(&msg, SMTPREVERSEPATH, reverse_path);
2420: smb_hfield_str(&msg, SENDER, sender);
2421: smb_hfield(&msg, SENDERNETTYPE, sizeof(nettype), &nettype);
2422: smb_hfield_str(&msg, SENDERNETADDR, sender_addr);
2423: if(msg.subj==NULL)
2424: smb_hfield(&msg, SUBJECT, 0, NULL);
2425:
2426: length=filelength(fileno(msgtxt))-ftell(msgtxt);
2427:
2428: if(startup->max_msg_size && length>startup->max_msg_size) {
2429: lprintf(LOG_WARNING,"%04d !SMTP message size (%lu) exceeds maximum: %lu bytes"
2430: ,socket,length,startup->max_msg_size);
2431: sockprintf(socket, "552 Message size (%lu) exceeds maximum: %lu bytes"
2432: ,length,startup->max_msg_size);
2433: subnum=INVALID_SUB;
2434: continue;
2435: }
2436:
2437: if((msgbuf=(char*)malloc(length+1))==NULL) {
2438: lprintf(LOG_CRIT,"%04d !SMTP ERROR allocating %d bytes of memory"
2439: ,socket,length+1);
2440: sockprintf(socket, "452 Insufficient system storage");
2441: subnum=INVALID_SUB;
2442: continue;
2443: }
2444: fread(msgbuf,length,1,msgtxt);
2445: msgbuf[length]=0; /* ASCIIZ */
2446:
2447: /* Do external JavaScript processing here? */
2448:
2449: if(subnum!=INVALID_SUB) { /* Message Base */
2450: if(relay_user.number==0)
2451: memset(&relay_user,0,sizeof(relay_user));
2452:
2453: if(!chk_ar(&scfg,scfg.grp[scfg.sub[subnum]->grp]->ar, &relay_user)
2454: || !chk_ar(&scfg,scfg.sub[subnum]->ar, &relay_user)
2455: || !chk_ar(&scfg,scfg.sub[subnum]->post_ar, &relay_user)) {
2456: lprintf(LOG_WARNING,"%04d !SMTP %s has insufficient access to post on %s"
2457: ,socket, sender_addr, scfg.sub[subnum]->sname);
2458: sockprintf(socket,"550 Insufficient access");
2459: subnum=INVALID_SUB;
2460: continue;
2461: }
2462:
2463: if(rcpt_name[0]==0)
2464: strcpy(rcpt_name,"All");
2465: smb_hfield_str(&msg, RECIPIENT, rcpt_name);
2466:
2467: smb.subnum=subnum;
2468: if((i=savemsg(&scfg, &smb, &msg, &client, msgbuf))!=SMB_SUCCESS) {
2469: lprintf(LOG_WARNING,"%04d !SMTP ERROR %d (%s) saving message"
2470: ,socket,i,smb.last_error);
2471: sockprintf(socket, "452 ERROR %d (%s) saving message"
2472: ,i,smb.last_error);
2473: } else {
2474: lprintf(LOG_INFO,"%04d SMTP %s posted a message on %s"
2475: ,socket, sender_addr, scfg.sub[subnum]->sname);
2476: sockprintf(socket,ok_rsp);
2477: signal_smtp_sem();
2478: }
2479: free(msgbuf);
2480: smb_close(&smb);
2481: subnum=INVALID_SUB;
2482: continue;
2483: }
2484:
2485: /* E-mail */
2486: smb.subnum=INVALID_SUB;
2487: i=savemsg(&scfg, &smb, &msg, &client, msgbuf);
2488: free(msgbuf);
2489: if(i!=SMB_SUCCESS) {
2490: smb_close(&smb);
2491: lprintf(LOG_ERR,"%04d !SMTP ERROR %d (%s) saving message"
2492: ,socket,i,smb.last_error);
2493: sockprintf(socket, "452 ERROR %d (%s) saving message"
2494: ,i,smb.last_error);
2495: continue;
2496: }
2497:
2498: sec_list=iniReadSectionList(rcptlst,NULL); /* Each section is a recipient */
2499: for(rcpt_count=0; sec_list!=NULL
2500: && sec_list[rcpt_count]!=NULL
2501: && rcpt_count<startup->max_recipients; rcpt_count++) {
2502:
2503: section=sec_list[rcpt_count];
2504:
2505: SAFECOPY(rcpt_name,iniReadString(rcptlst,section ,smb_hfieldtype(RECIPIENT),"unknown",value));
2506: usernum=iniReadInteger(rcptlst,section ,smb_hfieldtype(RECIPIENTEXT),0);
2507: agent=iniReadShortInt(rcptlst,section ,smb_hfieldtype(RECIPIENTAGENT),AGENT_PERSON);
2508: nettype=iniReadShortInt(rcptlst,section ,smb_hfieldtype(RECIPIENTNETTYPE),NET_NONE);
2509: sprintf(str,"#%u",usernum);
2510: SAFECOPY(rcpt_addr,iniReadString(rcptlst,section ,smb_hfieldtype(RECIPIENTNETADDR),str,value));
2511:
2512: if(nettype==NET_NONE /* Local destination */ && usernum==0) {
2513: lprintf(LOG_ERR,"%04d !SMTP can't deliver mail to user #0"
2514: ,socket);
2515: break;
2516: }
2517:
2518: if((i=smb_copymsgmem(&smb,&newmsg,&msg))!=SMB_SUCCESS) {
2519: lprintf(LOG_ERR,"%04d !SMTP ERROR %d (%s) copying message"
2520: ,socket, i, smb.last_error);
2521: break;
2522: }
2523:
2524: snprintf(hdrfield,sizeof(hdrfield),
2525: "Received: from %s (%s [%s])\r\n"
2526: " by %s [%s] (Synchronet Mail Server %s-%s) with %s\r\n"
2527: " for %s; %s"
2528: ,host_name,hello_name,host_ip
2529: ,startup->host_name,inet_ntoa(server_addr.sin_addr)
2530: ,revision,PLATFORM_DESC
2531: ,esmtp ? "ESMTP" : "SMTP"
2532: ,rcpt_name,msgdate(msg.hdr.when_imported,date));
2533: smb_hfield_str(&newmsg, RFC822HEADER, hdrfield);
2534:
2535: smb_hfield_str(&newmsg, RECIPIENT, rcpt_name);
2536:
2537: if(usernum) { /* Local destination or QWKnet routed */
2538: /* This is required for fixsmb to be able to rebuild the index */
2539: sprintf(str,"%u",usernum);
2540: smb_hfield_str(&newmsg, RECIPIENTEXT, str);
2541: }
2542: if(nettype!=NET_NONE) {
2543: smb_hfield(&newmsg, RECIPIENTNETTYPE, sizeof(nettype), &nettype);
2544: smb_hfield_str(&newmsg, RECIPIENTNETADDR, rcpt_addr);
2545: }
2546: if(agent!=newmsg.to_agent)
2547: smb_hfield(&newmsg, RECIPIENTAGENT, sizeof(agent), &agent);
2548:
2549: i=smb_addmsghdr(&smb,&newmsg,SMB_SELFPACK);
2550: smb_freemsgmem(&newmsg);
2551: if(i!=SMB_SUCCESS) {
2552: lprintf(LOG_ERR,"%04d !SMTP ERROR %d (%s) adding message header"
2553: ,socket, i, smb.last_error);
2554: break;
2555: }
2556: lprintf(LOG_INFO,"%04d SMTP Created message #%ld from %s to %s <%s>"
2557: ,socket, newmsg.hdr.number, sender, rcpt_name, rcpt_addr);
2558: if(!(startup->options&MAIL_OPT_NO_NOTIFY) && usernum
2559: && !dnsbl_recvhdr && !dnsbl_result.s_addr) {
2560: safe_snprintf(str,sizeof(str)
2561: ,"\7\1n\1hOn %.24s\r\n\1m%s \1n\1msent you e-mail from: "
2562: "\1h%s\1n\r\n"
2563: ,timestr(&scfg,(time_t*)&newmsg.hdr.when_imported.time,tmp)
2564: ,sender,sender_addr);
2565: if(!newmsg.idx.to) { /* Forwarding */
2566: strcat(str,"\1mand it was automatically forwarded to: \1h");
2567: strcat(str,user.netmail);
2568: strcat(str,"\1n\r\n");
2569: }
2570: putsmsg(&scfg, usernum, str);
2571: }
2572: }
2573: iniFreeStringList(sec_list);
2574: if(rcpt_count<1) {
2575: smb_freemsg_dfields(&smb,&msg,SMB_ALL_REFS);
2576: sockprintf(socket, "452 Insufficient system storage");
2577: }
2578: else {
2579: if(rcpt_count>1)
2580: smb_incmsg_dfields(&smb,&msg,(ushort)(rcpt_count-1));
2581: sockprintf(socket,ok_rsp);
2582: signal_smtp_sem();
2583: }
2584: #if 0 /* This shouldn't be necessary here */
2585: smb_close_da(&smb);
2586: #endif
2587: smb_close(&smb);
2588: continue;
2589: }
2590: if(buf[0]==0 && state==SMTP_STATE_DATA_HEADER) {
2591: state=SMTP_STATE_DATA_BODY; /* Null line separates header and body */
2592: lines=0;
2593: if(msgtxt!=NULL) {
2594: fprintf(msgtxt, "\r\n");
2595: hdr_len=ftell(msgtxt);
2596: }
2597: continue;
2598: }
2599: if(state==SMTP_STATE_DATA_BODY) {
2600: p=buf;
2601: if(*p=='.') p++; /* Transparency (RFC821 4.5.2) */
2602: if(msgtxt!=NULL)
2603: fprintf(msgtxt, "%s\r\n", p);
2604: lines++;
2605: /* release time-slices every x lines */
2606: if(startup->lines_per_yield &&
2607: !(lines%startup->lines_per_yield))
2608: YIELD();
2609: continue;
2610: }
2611: /* RFC822 Header parsing */
2612: if(startup->options&MAIL_OPT_DEBUG_RX_HEADER)
2613: lprintf(LOG_DEBUG,"%04d SMTP %s",socket, buf);
2614:
2615: if(!strnicmp(buf, "FROM:", 5))
2616: parse_mail_address(buf+5
2617: ,sender, sizeof(sender)-1
2618: ,sender_addr, sizeof(sender_addr)-1);
2619:
2620: if(msgtxt!=NULL)
2621: fprintf(msgtxt, "%s\r\n", buf);
2622: hdr_lines++;
2623: continue;
2624: }
2625: strip_ctrl(buf);
2626: lprintf(LOG_DEBUG,"%04d SMTP RX: %s", socket, buf);
2627: if(!strnicmp(buf,"HELO",4)) {
2628: p=buf+4;
2629: SKIP_WHITESPACE(p);
2630: SAFECOPY(hello_name,p);
2631: sockprintf(socket,"250 %s",startup->host_name);
2632: esmtp=FALSE;
2633: state=SMTP_STATE_HELO;
2634: cmd=SMTP_CMD_NONE;
2635: telegram=FALSE;
2636: subnum=INVALID_SUB;
2637: continue;
2638: }
2639: if(!strnicmp(buf,"EHLO",4)) {
2640: p=buf+4;
2641: SKIP_WHITESPACE(p);
2642: SAFECOPY(hello_name,p);
2643: sockprintf(socket,"250-%s",startup->host_name);
2644: sockprintf(socket,"250 AUTH PLAIN LOGIN CRAM-MD5");
2645: esmtp=TRUE;
2646: state=SMTP_STATE_HELO;
2647: cmd=SMTP_CMD_NONE;
2648: telegram=FALSE;
2649: subnum=INVALID_SUB;
2650: continue;
2651: }
2652: if((auth_login=(stricmp(buf,"AUTH LOGIN")==0))==TRUE
2653: || stricmp(buf,"AUTH PLAIN")==0) {
2654: if(auth_login)
2655: sockprintf(socket,"334 VXNlcm5hbWU6"); /* Base64-encoded "Username:" */
2656: else
2657: sockprintf(socket,"334 Username:");
2658: if((rd=sockreadline(socket, buf, sizeof(buf)))<1) {
2659: sockprintf(socket,badarg_rsp);
2660: continue;
2661: }
2662: if(startup->options&MAIL_OPT_DEBUG_RX_RSP)
2663: lprintf(LOG_DEBUG,"%04d RX: %s",socket,buf);
2664: if(auth_login) {
2665: if(b64_decode(user_name,sizeof(user_name),buf,rd)<1) {
2666: sockprintf(socket,badarg_rsp);
2667: continue;
2668: }
2669: } else
2670: SAFECOPY(user_name,buf);
2671:
2672: if(auth_login)
2673: sockprintf(socket,"334 UGFzc3dvcmQ6"); /* Base64-encoded "Password:" */
2674: else
2675: sockprintf(socket,"334 Password:");
2676: if((rd=sockreadline(socket, buf, sizeof(buf)))<1) {
2677: sockprintf(socket,badarg_rsp);
2678: continue;
2679: }
2680: if(startup->options&MAIL_OPT_DEBUG_RX_RSP)
2681: lprintf(LOG_DEBUG,"%04d RX: %s",socket,buf);
2682: if(auth_login) {
2683: if(b64_decode(user_pass,sizeof(user_pass),buf,rd)<1) {
2684: sockprintf(socket,badarg_rsp);
2685: continue;
2686: }
2687: } else
2688: SAFECOPY(user_pass,buf);
2689: if((relay_user.number=matchuser(&scfg,user_name,FALSE))==0) {
2690: if(scfg.sys_misc&SM_ECHO_PW)
2691: lprintf(LOG_WARNING,"%04d !SMTP UNKNOWN USER: %s (password: %s)"
2692: ,socket, user_name, user_pass);
2693: else
2694: lprintf(LOG_WARNING,"%04d !SMTP UNKNOWN USER: %s"
2695: ,socket, user_name);
2696: sockprintf(socket,badauth_rsp);
2697: continue;
2698: }
2699: if((i=getuserdat(&scfg, &relay_user))!=0) {
2700: lprintf(LOG_ERR,"%04d !SMTP ERROR %d getting data on user (%s)"
2701: ,socket, i, user_name);
2702: sockprintf(socket,badauth_rsp);
2703: relay_user.number=0;
2704: continue;
2705: }
2706: if(relay_user.misc&(DELETED|INACTIVE)) {
2707: lprintf(LOG_WARNING,"%04d !SMTP DELETED or INACTIVE user #%u (%s)"
2708: ,socket, relay_user.number, user_name);
2709: sockprintf(socket,badauth_rsp);
2710: relay_user.number=0;
2711: break;
2712: }
2713: if(stricmp(user_pass,relay_user.pass)) {
2714: if(scfg.sys_misc&SM_ECHO_PW)
2715: lprintf(LOG_WARNING,"%04d !SMTP FAILED Password attempt for user %s: '%s' expected '%s'"
2716: ,socket, user_name, user_pass, relay_user.pass);
2717: else
2718: lprintf(LOG_WARNING,"%04d !SMTP FAILED Password attempt for user %s"
2719: ,socket, user_name);
2720: sockprintf(socket,badauth_rsp);
2721: relay_user.number=0;
2722: break;
2723: }
2724: /* Update client display */
2725: client.user=relay_user.alias;
2726: client_on(socket,&client,TRUE /* update */);
2727:
2728: lprintf(LOG_INFO,"%04d SMTP %s authenticated using %s authentication"
2729: ,socket,relay_user.alias,auth_login ? "LOGIN" : "PLAIN");
2730: sockprintf(socket,auth_ok);
2731: continue;
2732: }
2733: if(!stricmp(buf,"AUTH CRAM-MD5")) {
2734: safe_snprintf(challenge,sizeof(challenge),"<%x%x%lx%lx@%s>"
2735: ,rand(),socket,(ulong)time(NULL),clock(),startup->host_name);
2736: #if 0
2737: lprintf(LOG_DEBUG,"%04d SMTP CRAM-MD5 challenge: %s"
2738: ,socket,challenge);
2739: #endif
2740: b64_encode(str,sizeof(str),challenge,0);
2741: sockprintf(socket,"334 %s",str);
2742: if((rd=sockreadline(socket, buf, sizeof(buf)))<1) {
2743: sockprintf(socket,badarg_rsp);
2744: continue;
2745: }
2746: if(startup->options&MAIL_OPT_DEBUG_RX_RSP)
2747: lprintf(LOG_DEBUG,"%04d RX: %s",socket,buf);
2748:
2749: if(b64_decode(response,sizeof(response),buf,rd)<1) {
2750: sockprintf(socket,badarg_rsp);
2751: continue;
2752: }
2753: #if 0
2754: lprintf(LOG_DEBUG,"%04d SMTP CRAM-MD5 response: %s"
2755: ,socket,response);
2756: #endif
2757: if((p=strrchr(response,' '))!=NULL)
2758: *(p++)=0;
2759: else
2760: p=response;
2761: SAFECOPY(user_name,response);
2762: if((relay_user.number=matchuser(&scfg,user_name,FALSE))==0) {
2763: lprintf(LOG_WARNING,"%04d !SMTP UNKNOWN USER: %s"
2764: ,socket, user_name);
2765: sockprintf(socket,badauth_rsp);
2766: continue;
2767: }
2768: if((i=getuserdat(&scfg, &relay_user))!=0) {
2769: lprintf(LOG_ERR,"%04d !SMTP ERROR %d getting data on user (%s)"
2770: ,socket, i, user_name);
2771: sockprintf(socket,badauth_rsp);
2772: relay_user.number=0;
2773: continue;
2774: }
2775: if(relay_user.misc&(DELETED|INACTIVE)) {
2776: lprintf(LOG_WARNING,"%04d !SMTP DELETED or INACTIVE user #%u (%s)"
2777: ,socket, relay_user.number, user_name);
2778: sockprintf(socket,badauth_rsp);
2779: relay_user.number=0;
2780: continue;
2781: }
2782: /* Calculate correct response */
2783: memset(secret,0,sizeof(secret));
2784: SAFECOPY(secret,relay_user.pass);
2785: strlwr(secret); /* this is case sensitive, so convert to lowercase first */
2786: for(i=0;i<sizeof(secret);i++)
2787: md5_data[i]=secret[i]^0x36; /* ipad */
2788: strcpy(md5_data+i,challenge);
2789: MD5_calc(digest,md5_data,sizeof(secret)+strlen(challenge));
2790: for(i=0;i<sizeof(secret);i++)
2791: md5_data[i]=secret[i]^0x5c; /* opad */
2792: memcpy(md5_data+i,digest,sizeof(digest));
2793: MD5_calc(digest,md5_data,sizeof(secret)+sizeof(digest));
2794: MD5_hex(str,digest);
2795: if(strcmp(p,str)) {
2796: lprintf(LOG_WARNING,"%04d !SMTP %s FAILED CRAM-MD5 authentication"
2797: ,socket,relay_user.alias);
2798: #if 0
2799: lprintf(LOG_DEBUG,"%04d !SMTP calc digest: %s"
2800: ,socket,str);
2801: lprintf(LOG_DEBUG,"%04d !SMTP resp digest: %s"
2802: ,socket,p);
2803: #endif
2804: sockprintf(socket,badauth_rsp);
2805: relay_user.number=0;
2806: continue;
2807: }
2808: /* Update client display */
2809: client.user=relay_user.alias;
2810: client_on(socket,&client,TRUE /* update */);
2811:
2812: lprintf(LOG_INFO,"%04d SMTP %s authenticated using CRAM-MD5 authentication"
2813: ,socket,relay_user.alias);
2814: sockprintf(socket,auth_ok);
2815: continue;
2816: }
2817: if(!strnicmp(buf,"AUTH",4)) {
2818: sockprintf(socket,"504 Unrecognized authentication type.");
2819: continue;
2820: }
2821: if(!stricmp(buf,"QUIT")) {
2822: sockprintf(socket,"221 %s Service closing transmission channel",startup->host_name);
2823: break;
2824: }
2825: if(!stricmp(buf,"NOOP")) {
2826: sockprintf(socket, ok_rsp);
2827: badcmds=0;
2828: continue;
2829: }
2830: if(state<SMTP_STATE_HELO) {
2831: /* RFC 821 4.1.1 "The first command in a session must be the HELO command." */
2832: lprintf(LOG_WARNING,"%04d !SMTP MISSING 'HELO' command",socket);
2833: sockprintf(socket, badseq_rsp);
2834: continue;
2835: }
2836: if(!stricmp(buf,"TURN")) {
2837: sockprintf(socket,"502 command not supported");
2838: badcmds=0;
2839: continue;
2840: }
2841: if(!stricmp(buf,"RSET")) {
2842: smb_freemsgmem(&msg);
2843: memset(&msg,0,sizeof(smbmsg_t)); /* Initialize message header */
2844: reverse_path[0]=0;
2845: state=SMTP_STATE_HELO;
2846: cmd=SMTP_CMD_NONE;
2847: telegram=FALSE;
2848: subnum=INVALID_SUB;
2849:
2850: /* reset recipient list */
2851: if((rcptlst=freopen(rcptlst_fname,"w+",rcptlst))==NULL) {
2852: lprintf(LOG_ERR,"%04d !SMTP ERROR %d re-opening %s"
2853: ,socket, errno, rcptlst_fname);
2854: sockprintf(socket,sys_error);
2855: break;
2856: }
2857: rcpt_count=0;
2858:
2859: sockprintf(socket,ok_rsp);
2860: badcmds=0;
2861: lprintf(LOG_INFO,"%04d SMTP Session reset",socket);
2862: continue;
2863: }
2864: if(!strnicmp(buf,"MAIL FROM:",10)
2865: || !strnicmp(buf,"SEND FROM:",10) /* Send a Message (Telegram) to a local ONLINE user */
2866: || !strnicmp(buf,"SOML FROM:",10) /* Send OR Mail a Message to a local user */
2867: || !strnicmp(buf,"SAML FROM:",10) /* Send AND Mail a Message to a local user */
2868: ) {
2869: p=buf+10;
2870: if(!chk_email_addr(socket,p,host_name,host_ip,NULL,NULL,"REVERSE PATH")) {
2871: sockprintf(socket, "554 Sender not allowed.");
2872: break;
2873: }
2874: SKIP_WHITESPACE(p);
2875: SAFECOPY(reverse_path,p);
2876:
2877: /* Update client display */
2878: if(relay_user.number==0) {
2879: client.user=reverse_path;
2880: client_on(socket,&client,TRUE /* update */);
2881: }
2882:
2883: /* Setup state */
2884: state=SMTP_STATE_MAIL_FROM;
2885: if(!strnicmp(buf,"MAIL FROM:",10))
2886: cmd=SMTP_CMD_MAIL;
2887: else if(!strnicmp(buf,"SEND FROM:",10))
2888: cmd=SMTP_CMD_SEND;
2889: else if(!strnicmp(buf,"SOML FROM:",10))
2890: cmd=SMTP_CMD_SOML;
2891: else if(!strnicmp(buf,"SAML FROM:",10))
2892: cmd=SMTP_CMD_SAML;
2893:
2894: /* reset recipient list */
2895: if((rcptlst=freopen(rcptlst_fname,"w+",rcptlst))==NULL) {
2896: lprintf(LOG_ERR,"%04d !SMTP ERROR %d re-opening %s"
2897: ,socket, errno, rcptlst_fname);
2898: sockprintf(socket,sys_error);
2899: break;
2900: }
2901: rcpt_count=0;
2902: sockprintf(socket,ok_rsp);
2903: badcmds=0;
2904: continue;
2905: }
2906:
2907: #if 0 /* No one uses this command */
2908: if(!strnicmp(buf,"VRFY",4)) {
2909: p=buf+4;
2910: SKIP_WHITESPACE(p);
2911: if(*p==0) {
2912: sockprintf(socket,"550 No user specified.");
2913: continue;
2914: }
2915: #endif
2916:
2917: /* Add to Recipient list */
2918: if(!strnicmp(buf,"RCPT TO:",8)) {
2919:
2920: if(state<SMTP_STATE_MAIL_FROM) {
2921: lprintf(LOG_WARNING,"%04d !SMTP MISSING 'MAIL' command",socket);
2922: sockprintf(socket, badseq_rsp);
2923: continue;
2924: }
2925:
2926: if(spy==NULL && trashcan(&scfg,reverse_path,"smtpspy")) {
2927: sprintf(str,"%ssmtpspy.txt", scfg.logs_dir);
2928: spy=fopen(str,"a");
2929: }
2930:
2931: p=buf+8;
2932: SKIP_WHITESPACE(p);
2933: SAFECOPY(str,p);
2934: p=strrchr(str,'<');
2935: if(p==NULL)
2936: p=str;
2937: else
2938: p++;
2939:
2940: truncstr(str,">"); /* was truncating at space too */
2941:
2942: routed=FALSE;
2943: forward=FALSE;
2944: no_forward=FALSE;
2945: if(!strnicmp(p,FORWARD,strlen(FORWARD))) {
2946: forward=TRUE; /* force forward to user's netmail address */
2947: p+=strlen(FORWARD);
2948: }
2949: if(!strnicmp(p,NO_FORWARD,strlen(NO_FORWARD))) {
2950: no_forward=TRUE; /* do not forward to user's netmail address */
2951: p+=strlen(NO_FORWARD);
2952: }
2953:
2954: if(*p==0) {
2955: lprintf(LOG_WARNING,"%04d !SMTP NO RECIPIENT SPECIFIED"
2956: ,socket);
2957: sockprintf(socket, "500 No recipient specified");
2958: continue;
2959: }
2960:
2961: rcpt_name[0]=0;
2962: SAFECOPY(rcpt_addr,p);
2963:
2964: /* Check recipient counter */
2965: if(rcpt_count>=startup->max_recipients) {
2966: lprintf(LOG_WARNING,"%04d !SMTP MAXIMUM RECIPIENTS (%d) REACHED"
2967: ,socket, startup->max_recipients);
2968: sprintf(tmp,"Maximum recipient count (%d)",startup->max_recipients);
2969: spamlog(&scfg, "SMTP", "REFUSED", tmp
2970: ,host_name, host_ip, rcpt_addr, reverse_path);
2971: sockprintf(socket, "552 Too many recipients");
2972: continue;
2973: }
2974:
2975: /* Check for SPAM bait recipient */
2976: if(findstr(rcpt_addr,spam_bait)) {
2977: SAFEPRINTF(str,"SPAM BAIT (%s) taken", rcpt_addr);
2978: lprintf(LOG_WARNING,"%04d !SMTP %s by: %s"
2979: ,socket, str, reverse_path);
2980: strcpy(tmp,"REFUSED");
2981: if(dnsbl_result.s_addr==0) { /* Don't double-filter */
2982: lprintf(LOG_WARNING,"%04d !BLOCKING IP ADDRESS: %s in %s", socket, host_ip, spam_block);
2983: filter_ip(&scfg, "SMTP", str, host_name, host_ip, reverse_path, spam_block);
2984: strcat(tmp," and BLOCKED");
2985: }
2986: spamlog(&scfg, "SMTP", tmp, "Attempted recipient in SPAM BAIT list"
2987: ,host_name, host_ip, rcpt_addr, reverse_path);
2988: break;
2989: }
2990:
2991: /* Check for blocked recipients */
2992: if(!chk_email_addr(socket,rcpt_addr,host_name,host_ip,rcpt_addr,reverse_path,"RECIPIENT")) {
2993: sockprintf(socket, "550 Unknown User:%s", buf+8);
2994: continue;
2995: }
2996:
2997: if(relay_user.number==0 && dnsbl_result.s_addr && startup->options&MAIL_OPT_DNSBL_BADUSER) {
2998: lprintf(LOG_WARNING,"%04d !SMTP REFUSED MAIL from blacklisted server"
2999: ,socket);
3000: SAFEPRINTF2(str,"Listed on %s as %s", dnsbl, inet_ntoa(dnsbl_result));
3001: spamlog(&scfg, "SMTP", "REFUSED", str, host_name, host_ip, rcpt_addr, reverse_path);
3002: sockprintf(socket
3003: ,"550 Mail from %s refused due to listing at %s"
3004: ,host_ip, dnsbl);
3005: continue;
3006: }
3007:
3008: /* Check for full address aliases */
3009: p=alias(&scfg,p,alias_buf);
3010: if(p==alias_buf)
3011: lprintf(LOG_INFO,"%04d SMTP ADDRESS ALIAS: %s",socket,p);
3012:
3013: tp=strrchr(p,'@');
3014: if(cmd==SMTP_CMD_MAIL && tp!=NULL) {
3015:
3016: /* RELAY */
3017: dest_port=server_addr.sin_port;
3018: SAFECOPY(dest_host,tp+1);
3019: cp=strrchr(dest_host,':');
3020: if(cp!=NULL) {
3021: *cp=0;
3022: dest_port=atoi(cp+1);
3023: }
3024: sprintf(domain_list,"%sdomains.cfg",scfg.ctrl_dir);
3025: if((stricmp(dest_host,scfg.sys_inetaddr)!=0
3026: && stricmp(dest_host,startup->host_name)!=0
3027: && resolve_ip(dest_host)!=server_addr.sin_addr.s_addr
3028: && findstr(dest_host,domain_list)==FALSE)
3029: || dest_port!=server_addr.sin_port) {
3030:
3031: sprintf(relay_list,"%srelay.cfg",scfg.ctrl_dir);
3032: if(relay_user.number==0 /* not authenticated, search for IP */
3033: && startup->options&MAIL_OPT_SMTP_AUTH_VIA_IP) {
3034: relay_user.number=userdatdupe(&scfg, 0, U_NOTE, LEN_NOTE, host_ip, FALSE);
3035: if(relay_user.number) {
3036: getuserdat(&scfg,&relay_user);
3037: if(relay_user.laston < time(NULL)-(60*60)) /* logon in past hour? */
3038: relay_user.number=0;
3039: }
3040: } else
3041: getuserdat(&scfg,&relay_user);
3042: if(p!=alias_buf /* forced relay by alias */ &&
3043: (!(startup->options&MAIL_OPT_ALLOW_RELAY)
3044: || relay_user.number==0
3045: || relay_user.rest&(FLAG('G')|FLAG('M'))) &&
3046: !findstr(host_name,relay_list) &&
3047: !findstr(host_ip,relay_list)) {
3048: lprintf(LOG_WARNING,"%04d !SMTP ILLEGAL RELAY ATTEMPT from %s [%s] to %s"
3049: ,socket, reverse_path, host_ip, p);
3050: SAFEPRINTF(tmp,"Relay attempt to: %s", p);
3051: spamlog(&scfg, "SMTP", "REFUSED", tmp, host_name, host_ip, rcpt_addr, reverse_path);
3052: if(startup->options&MAIL_OPT_ALLOW_RELAY)
3053: sockprintf(socket, "553 Relaying through this server "
3054: "requires authentication. "
3055: "Please authenticate before sending.");
3056: else
3057: sockprintf(socket, "550 Relay not allowed.");
3058: break;
3059: }
3060:
3061: if(relay_user.number==0)
3062: SAFECOPY(relay_user.alias,"Unknown User");
3063:
3064: lprintf(LOG_INFO,"%04d SMTP %s relaying to external mail service: %s"
3065: ,socket, relay_user.alias, tp+1);
3066:
3067: fprintf(rcptlst,"[%u]\n",rcpt_count++);
3068: fprintf(rcptlst,"%s=%s\n",smb_hfieldtype(RECIPIENT),rcpt_addr);
3069: fprintf(rcptlst,"%s=%u\n",smb_hfieldtype(RECIPIENTNETTYPE),NET_INTERNET);
3070: fprintf(rcptlst,"%s=%s\n",smb_hfieldtype(RECIPIENTNETADDR),p);
3071:
3072: sockprintf(socket,ok_rsp);
3073: state=SMTP_STATE_RCPT_TO;
3074: continue;
3075: }
3076: }
3077: if(tp!=NULL)
3078: *tp=0; /* truncate at '@' */
3079:
3080: tp=strchr(p,'!'); /* Routed QWKnet mail in <qwkid!user@host> format */
3081: if(tp!=NULL) {
3082: *(tp++)=0;
3083: SKIP_CHAR(tp,'"'); /* Skip '"' */
3084: truncstr(tp,"\""); /* Strip '"' */
3085: SAFECOPY(rcpt_addr,tp);
3086: routed=TRUE;
3087: }
3088:
3089: FIND_ALPHANUMERIC(p); /* Skip '<' or '"' */
3090: truncstr(p,"\"");
3091:
3092: p=alias(&scfg,p,name_alias_buf);
3093: if(p==name_alias_buf)
3094: lprintf(LOG_INFO,"%04d SMTP NAME ALIAS: %s",socket,p);
3095:
3096: if(!strnicmp(p,"sub:",4)) { /* Post on a sub-board */
3097: p+=4;
3098: for(i=0;i<scfg.total_subs;i++)
3099: if(!stricmp(p,scfg.sub[i]->code))
3100: break;
3101: if(i>=scfg.total_subs) {
3102: lprintf(LOG_WARNING,"%04d !SMTP UNKNOWN SUB-BOARD: %s", socket, p);
3103: sockprintf(socket, "550 Unknown sub-board: %s", p);
3104: continue;
3105: }
3106: subnum=i;
3107: sockprintf(socket,ok_rsp);
3108: state=SMTP_STATE_RCPT_TO;
3109: rcpt_count++;
3110: continue;
3111: }
3112:
3113: memset(mailproc_match,FALSE,sizeof(BOOL)*mailproc_count);
3114: for(i=0;i<mailproc_count;i++) {
3115: if(mailproc_list[i].to!=NULL) {
3116: for(j=0;mailproc_list[i].to[j]!=NULL;j++) {
3117: if(stricmp(p,mailproc_list[i].to[j])==0) {
3118: mailproc_match[i]=TRUE;
3119: if(!mailproc_list[i].passthru)
3120: break;
3121: }
3122: }
3123: if(mailproc_list[i].to[j]!=NULL)
3124: break;
3125: }
3126: }
3127: /* destined for an external mail processor */
3128: if(i<mailproc_count) {
3129: fprintf(rcptlst,"[%u]\n",rcpt_count++);
3130: fprintf(rcptlst,"%s=%s\n",smb_hfieldtype(RECIPIENT),rcpt_addr);
3131: #if 0 /* should we fall-through to the sysop account? */
3132: fprintf(rcptlst,"%s=%u\n",smb_hfieldtype(RECIPIENTEXT),1);
3133: #endif
3134: lprintf(LOG_INFO,"%04d SMTP Routing mail for %s to External Mail Processor: %s"
3135: ,socket, rcpt_addr, mailproc_list[i].cmdline);
3136: sockprintf(socket,ok_rsp);
3137: state=SMTP_STATE_RCPT_TO;
3138: continue;
3139: }
3140:
3141: usernum=0; /* unknown user at this point */
3142:
3143: if(routed) {
3144: SAFECOPY(qwkid,p);
3145: truncstr(qwkid,"/");
3146: /* Search QWKnet hub-IDs for route destination */
3147: for(i=0;i<scfg.total_qhubs;i++) {
3148: if(!stricmp(qwkid,scfg.qhub[i]->id))
3149: break;
3150: }
3151: if(i<scfg.total_qhubs) { /* found matching QWKnet Hub */
3152:
3153: lprintf(LOG_INFO,"%04d SMTP Routing mail for %s <%s> to QWKnet Hub: %s"
3154: ,socket, rcpt_addr, p, scfg.qhub[i]->id);
3155:
3156: fprintf(rcptlst,"[%u]\n",rcpt_count++);
3157: fprintf(rcptlst,"%s=%s\n",smb_hfieldtype(RECIPIENT),rcpt_addr);
3158: fprintf(rcptlst,"%s=%u\n",smb_hfieldtype(RECIPIENTNETTYPE),NET_QWK);
3159: fprintf(rcptlst,"%s=%s\n",smb_hfieldtype(RECIPIENTNETADDR),p);
3160:
3161: sockprintf(socket,ok_rsp);
3162: state=SMTP_STATE_RCPT_TO;
3163: continue;
3164: }
3165: }
3166:
3167: if((p==name_alias_buf || startup->options&MAIL_OPT_ALLOW_RX_BY_NUMBER)
3168: && isdigit(*p)) {
3169: usernum=atoi(p); /* RX by user number */
3170: /* verify usernum */
3171: username(&scfg,usernum,str);
3172: if(!str[0] || !stricmp(str,"DELETED USER"))
3173: usernum=0;
3174: p=str;
3175: } else {
3176: /* RX by "user alias", "user.alias" or "user_alias" */
3177: usernum=matchuser(&scfg,p,startup->options&MAIL_OPT_ALLOW_SYSOP_ALIASES);
3178:
3179: if(!usernum) { /* RX by "real name", "real.name", or "sysop.alias" */
3180:
3181: /* convert "user.name" to "user name" */
3182: SAFECOPY(rcpt_name,p);
3183: for(tp=rcpt_name;*tp;tp++)
3184: if(*tp=='.') *tp=' ';
3185:
3186: if(!stricmp(p,scfg.sys_op) || !stricmp(rcpt_name,scfg.sys_op))
3187: usernum=1; /* RX by "sysop.alias" */
3188:
3189: if(!usernum && scfg.msg_misc&MM_REALNAME) /* RX by "real name" */
3190: usernum=userdatdupe(&scfg, 0, U_NAME, LEN_NAME, p, FALSE);
3191:
3192: if(!usernum && scfg.msg_misc&MM_REALNAME) /* RX by "real.name" */
3193: usernum=userdatdupe(&scfg, 0, U_NAME, LEN_NAME, rcpt_name, FALSE);
3194: }
3195: }
3196: if(!usernum && startup->default_user[0]) {
3197: usernum=matchuser(&scfg,startup->default_user,TRUE /* sysop_alias */);
3198: if(usernum)
3199: lprintf(LOG_INFO,"%04d SMTP Forwarding mail for UNKNOWN USER to default user: %s #%u"
3200: ,socket,startup->default_user,usernum);
3201: else
3202: lprintf(LOG_WARNING,"%04d !SMTP UNKNOWN DEFAULT USER: %s"
3203: ,socket,startup->default_user);
3204: }
3205:
3206: if(!usernum) {
3207: lprintf(LOG_WARNING,"%04d !SMTP UNKNOWN USER:%s", socket, buf+8);
3208: sockprintf(socket, "550 Unknown User:%s", buf+8);
3209: continue;
3210: }
3211: user.number=usernum;
3212: if((i=getuserdat(&scfg, &user))!=0) {
3213: lprintf(LOG_ERR,"%04d !SMTP ERROR %d getting data on user #%u (%s)"
3214: ,socket, i, usernum, p);
3215: sockprintf(socket, "550 Unknown User:%s", buf+8);
3216: continue;
3217: }
3218: if(user.misc&(DELETED|INACTIVE)) {
3219: lprintf(LOG_WARNING,"%04d !SMTP DELETED or INACTIVE user #%u (%s)"
3220: ,socket, usernum, p);
3221: sockprintf(socket, "550 Unknown User:%s", buf+8);
3222: continue;
3223: }
3224: if(cmd==SMTP_CMD_SEND) { /* Check if user online */
3225: for(i=0;i<scfg.sys_nodes;i++) {
3226: getnodedat(&scfg, i+1, &node, 0);
3227: if(node.status==NODE_INUSE && node.useron==user.number
3228: && !(node.misc&NODE_POFF))
3229: break;
3230: }
3231: if(i>=scfg.sys_nodes) {
3232: lprintf(LOG_WARNING,"%04d !Attempt to send telegram to unavailable user #%u (%s)"
3233: ,socket, user.number, user.alias);
3234: sockprintf(socket,"450 User unavailable");
3235: continue;
3236: }
3237: }
3238: if(cmd==SMTP_CMD_MAIL) {
3239: #if 0 /* implement later */
3240: if(useron.etoday>=cfg.level_emailperday[useron.level]
3241: && !(useron.rest&FLAG('Q'))) {
3242: bputs(text[TooManyEmailsToday]);
3243: continue;
3244: }
3245: #endif
3246: } else
3247: telegram=TRUE;
3248:
3249: fprintf(rcptlst,"[%u]\n",rcpt_count++);
3250: fprintf(rcptlst,"%s=%s\n",smb_hfieldtype(RECIPIENT),rcpt_addr);
3251: fprintf(rcptlst,"%s=%u\n",smb_hfieldtype(RECIPIENTEXT),user.number);
3252:
3253:
3254: /* Forward to Internet */
3255: tp=strrchr(user.netmail,'@');
3256: if(!telegram
3257: && !routed
3258: && !no_forward
3259: && scfg.sys_misc&SM_FWDTONET
3260: && (user.misc&NETMAIL || forward)
3261: && tp!=NULL && smb_netaddr_type(user.netmail)==NET_INTERNET
3262: && !strstr(tp,scfg.sys_inetaddr)) {
3263: lprintf(LOG_INFO,"%04d SMTP Forwarding to: %s"
3264: ,socket, user.netmail);
3265: fprintf(rcptlst,"%s=%u\n",smb_hfieldtype(RECIPIENTNETTYPE),NET_INTERNET);
3266: fprintf(rcptlst,"%s=%s\n",smb_hfieldtype(RECIPIENTNETADDR),user.netmail);
3267: sockprintf(socket,"251 User not local; will forward to %s", user.netmail);
3268: } else { /* Local (no-forward) */
3269: if(routed) { /* QWKnet */
3270: fprintf(rcptlst,"%s=%u\n",smb_hfieldtype(RECIPIENTNETTYPE),NET_QWK);
3271: fprintf(rcptlst,"%s=%s\n",smb_hfieldtype(RECIPIENTNETADDR),user.alias);
3272: }
3273: sockprintf(socket,ok_rsp);
3274: }
3275: state=SMTP_STATE_RCPT_TO;
3276: continue;
3277: }
3278: /* Message Data (header and body) */
3279: if(!strnicmp(buf,"DATA",4)) {
3280: if(state<SMTP_STATE_RCPT_TO) {
3281: lprintf(LOG_WARNING,"%04d !SMTP MISSING 'RCPT TO' command", socket);
3282: sockprintf(socket, badseq_rsp);
3283: continue;
3284: }
3285: if(msgtxt!=NULL) {
3286: fclose(msgtxt), msgtxt=NULL;
3287: if(!(startup->options&MAIL_OPT_DEBUG_RX_BODY))
3288: unlink(msgtxt_fname);
3289: }
3290: SAFEPRINTF2(msgtxt_fname,"%sSBBS_SMTP.%s.msg", scfg.temp_dir, session_id);
3291: if((msgtxt=fopen(msgtxt_fname,"w+b"))==NULL) {
3292: lprintf(LOG_ERR,"%04d !SMTP ERROR %d opening %s"
3293: ,socket, errno, msgtxt_fname);
3294: sockprintf(socket, "452 Insufficient system storage");
3295: continue;
3296: }
3297: /* These vars are potentially over-written by parsing an RFC822 header */
3298: /* get sender_addr */
3299: p=strchr(reverse_path,'<');
3300: if(p==NULL)
3301: p=reverse_path;
3302: else
3303: p++;
3304: SAFECOPY(sender_addr,p);
3305: truncstr(sender_addr,">");
3306: /* get sender */
3307: SAFECOPY(sender,sender_addr);
3308: if(truncstr(sender,"@")==NULL)
3309: sender[0]=0;
3310:
3311: sockprintf(socket, "354 send the mail data, end with <CRLF>.<CRLF>");
3312: if(telegram)
3313: state=SMTP_STATE_DATA_BODY; /* No RFC headers in Telegrams */
3314: else
3315: state=SMTP_STATE_DATA_HEADER;
3316: hdr_lines=0;
3317: continue;
3318: }
3319: sockprintf(socket,"500 Syntax error");
3320: lprintf(LOG_WARNING,"%04d !SMTP UNSUPPORTED COMMAND: '%s'", socket, buf);
3321: if(++badcmds>9) {
3322: lprintf(LOG_WARNING,"%04d !TOO MANY INVALID COMMANDS (%u)",socket,badcmds);
3323: break;
3324: }
3325: }
3326:
3327: /* Free up resources here */
3328: smb_freemsgmem(&msg);
3329:
3330: if(msgtxt!=NULL) {
3331: fclose(msgtxt);
3332: if(!(startup->options&MAIL_OPT_DEBUG_RX_BODY))
3333: unlink(msgtxt_fname);
3334: }
3335: if(rcptlst!=NULL) {
3336: fclose(rcptlst);
3337: unlink(rcptlst_fname);
3338: }
3339: if(spy!=NULL)
3340: fclose(spy);
3341:
3342: status(STATUS_WFC);
3343:
3344: if(active_clients)
3345: active_clients--, update_clients();
3346: client_off(socket);
3347:
3348: thread_down();
3349: lprintf(LOG_DEBUG,"%04d SMTP RX Session thread terminated (%u threads remain, %lu clients served)"
3350: ,socket, thread_count, served);
3351:
3352: /* Must be last */
3353: mail_close_socket(socket);
3354: }
3355:
3356: BOOL bounce(smb_t* smb, smbmsg_t* msg, char* err, BOOL immediate)
3357: {
3358: char str[128];
3359: char attempts[64];
3360: int i;
3361: ushort agent=AGENT_SMTPSYSMSG;
3362: smbmsg_t newmsg;
3363:
3364: msg->hdr.delivery_attempts++;
3365: lprintf(LOG_WARNING,"0000 !Delivery attempt #%u FAILED (%s) for message #%lu from %s to %s"
3366: ,msg->hdr.delivery_attempts
3367: ,err
3368: ,msg->hdr.number
3369: ,msg->from
3370: ,msg->to_net.addr);
3371:
3372: if((i=smb_updatemsg(smb,msg))!=SMB_SUCCESS) {
3373: lprintf(LOG_ERR,"0000 !BOUNCE ERROR %d (%s) incrementing delivery attempt counter"
3374: ,i, smb->last_error);
3375: return(FALSE);
3376: }
3377:
3378: if(!immediate && msg->hdr.delivery_attempts < startup->max_delivery_attempts)
3379: return(TRUE);
3380:
3381: newmsg=*msg;
3382: /* Mark original message as deleted */
3383: msg->hdr.attr|=MSG_DELETE;
3384:
3385: i=smb_updatemsg(smb,msg);
3386: if(msg->hdr.auxattr&MSG_FILEATTACH)
3387: delfattach(&scfg,msg);
3388: if(i!=SMB_SUCCESS) {
3389: lprintf(LOG_ERR,"0000 !BOUNCE ERROR %d (%s) deleting message"
3390: ,i, smb->last_error);
3391: return(FALSE);
3392: }
3393:
3394: if(msg->from_agent!=AGENT_PERSON /* don't bounce 'bounce messages' */
3395: || (msg->idx.from==0 && msg->from_net.type==NET_NONE)
3396: || (msg->reverse_path!=NULL && *msg->reverse_path==0)) {
3397: lprintf(LOG_WARNING,"0000 !Deleted undeliverable message from %s", msg->from);
3398: return(TRUE);
3399: }
3400:
3401: lprintf(LOG_WARNING,"0000 !Bouncing message back to %s", msg->from);
3402:
3403: newmsg.hfield=NULL;
3404: newmsg.hfield_dat=NULL;
3405: newmsg.total_hfields=0;
3406: newmsg.hdr.delivery_attempts=0;
3407:
3408: SAFEPRINTF(str,"Delivery failure: %s",newmsg.subj);
3409: smb_hfield_str(&newmsg, SUBJECT, str);
3410: smb_hfield_str(&newmsg, RECIPIENT, newmsg.from);
3411: if(newmsg.from_ext!=NULL) { /* Back to sender */
3412: smb_hfield_str(&newmsg, RECIPIENTEXT, newmsg.from_ext);
3413: newmsg.from_ext=NULL; /* Clear the sender extension */
3414: }
3415:
3416: if((newmsg.from_net.type==NET_QWK || newmsg.from_net.type==NET_INTERNET)
3417: && newmsg.reverse_path!=NULL) {
3418: smb_hfield(&newmsg, RECIPIENTNETTYPE, sizeof(newmsg.from_net.type), &newmsg.from_net.type);
3419: smb_hfield_str(&newmsg, RECIPIENTNETADDR, newmsg.reverse_path);
3420: }
3421: strcpy(str,"Mail Delivery Subsystem");
3422: smb_hfield_str(&newmsg, SENDER, str);
3423: smb_hfield(&newmsg, SENDERAGENT, sizeof(agent), &agent);
3424:
3425: /* Put error message in subject for now */
3426: if(msg->hdr.delivery_attempts>1)
3427: sprintf(attempts,"after %u attempts", msg->hdr.delivery_attempts);
3428: else
3429: attempts[0]=0;
3430: SAFEPRINTF2(str,"%s reporting delivery failure of message %s"
3431: ,startup->host_name, attempts);
3432: smb_hfield_str(&newmsg, SMB_COMMENT, str);
3433: SAFEPRINTF2(str,"from %s to %s\r\n"
3434: ,msg->reverse_path==NULL ? msg->from : msg->reverse_path
3435: ,(char*)msg->to_net.addr);
3436: smb_hfield_str(&newmsg, SMB_COMMENT, str);
3437: strcpy(str,"Reason:");
3438: smb_hfield_str(&newmsg, SMB_COMMENT, str);
3439: smb_hfield_str(&newmsg, SMB_COMMENT, err);
3440: smb_hfield_str(&newmsg, SMB_COMMENT, "\r\nOriginal message text follows:\r\n");
3441:
3442: if((i=smb_addmsghdr(smb,&newmsg,SMB_SELFPACK))!=SMB_SUCCESS)
3443: lprintf(LOG_ERR,"0000 !BOUNCE ERROR %d (%s) adding message header"
3444: ,i,smb->last_error);
3445: else {
3446: lprintf(LOG_WARNING,"0000 !Delivery failure notification (message #%ld) created for %s"
3447: ,newmsg.hdr.number, newmsg.from);
3448: if((i=smb_incmsg_dfields(smb,&newmsg,1))!=SMB_SUCCESS)
3449: lprintf(LOG_ERR,"0000 !BOUNCE ERROR %d (%s) incrementing data allocation units"
3450: ,i,smb->last_error);
3451: }
3452:
3453: newmsg.dfield=NULL; /* Don't double-free the data fields */
3454: newmsg.hdr.total_dfields=0;
3455: smb_freemsgmem(&newmsg);
3456:
3457: return(TRUE);
3458: }
3459:
3460: static int remove_msg_intransit(smb_t* smb, smbmsg_t* msg)
3461: {
3462: int i;
3463:
3464: if((i=smb_lockmsghdr(smb,msg))!=SMB_SUCCESS) {
3465: lprintf(LOG_WARNING,"0000 !SEND ERROR %d (%s) locking message header #%lu"
3466: ,i, smb->last_error, msg->idx.number);
3467: return(i);
3468: }
3469: msg->hdr.netattr&=~MSG_INTRANSIT;
3470: i=smb_putmsghdr(smb,msg);
3471: smb_unlockmsghdr(smb,msg);
3472:
3473: if(i!=0)
3474: lprintf(LOG_ERR,"0000 !SEND ERROR %d (%s) writing message header #%lu"
3475: ,i, smb->last_error, msg->idx.number);
3476:
3477: return(i);
3478: }
3479:
3480: void get_dns_server(char* dns_server, size_t len)
3481: {
3482: str_list_t list;
3483: size_t count;
3484:
3485: sprintf(dns_server,"%.*s",len,startup->dns_server);
3486: if(!isalnum(dns_server[0])) {
3487: if((list=getNameServerList())!=NULL) {
3488: if((count=strListCount(list))>0) {
3489: sprintf(dns_server,"%.*s",len,list[xp_random(count)]);
3490: lprintf(LOG_DEBUG,"0000 SEND using auto-detected DNS server address: %s"
3491: ,dns_server);
3492: }
3493: freeNameServerList(list);
3494: }
3495: }
3496: }
3497:
3498: #ifdef __BORLANDC__
3499: #pragma argsused
3500: #endif
3501: static void sendmail_thread(void* arg)
3502: {
3503: int i,j;
3504: char to[128];
3505: char mx[128];
3506: char mx2[128];
3507: char err[1024];
3508: char buf[512];
3509: char str[128];
3510: char resp[512];
3511: char toaddr[256];
3512: char fromaddr[256];
3513: char challenge[256];
3514: char secret[64];
3515: char md5_data[384];
3516: char digest[MD5_DIGEST_SIZE];
3517: char numeric_ip[16];
3518: char domain_list[MAX_PATH+1];
3519: char dns_server[16];
3520: char* server;
3521: char* msgtxt=NULL;
3522: char* p;
3523: char* tp;
3524: ushort port;
3525: ulong last_msg=0;
3526: ulong ip_addr;
3527: ulong dns;
3528: ulong lines;
3529: BOOL success;
3530: BOOL first_cycle=TRUE;
3531: SOCKET sock=INVALID_SOCKET;
3532: SOCKADDR_IN addr;
3533: SOCKADDR_IN server_addr;
3534: time_t last_scan=0;
3535: smb_t smb;
3536: smbmsg_t msg;
3537: mail_t* mail;
3538: long msgs;
3539: long l;
3540: BOOL sending_locally=FALSE;
3541:
3542: SetThreadName("SendMail Thread");
3543: thread_up(TRUE /* setuid */);
3544:
3545: sendmail_running=TRUE;
3546: terminate_sendmail=FALSE;
3547:
3548: lprintf(LOG_DEBUG,"0000 SendMail thread started");
3549:
3550: memset(&msg,0,sizeof(msg));
3551: memset(&smb,0,sizeof(smb));
3552:
3553: while(server_socket!=INVALID_SOCKET && !terminate_sendmail) {
3554:
3555: if(startup->options&MAIL_OPT_NO_SENDMAIL) {
3556: sem_trywait_block(&sendmail_wakeup_sem,1000);
3557: continue;
3558: }
3559:
3560: if(active_sendmail!=0)
3561: active_sendmail=0, update_clients();
3562:
3563: smb_close(&smb);
3564:
3565: if(sock!=INVALID_SOCKET) {
3566: mail_close_socket(sock);
3567: sock=INVALID_SOCKET;
3568: }
3569:
3570: if(msgtxt!=NULL) {
3571: smb_freemsgtxt(msgtxt);
3572: msgtxt=NULL;
3573: }
3574:
3575: smb_freemsgmem(&msg);
3576:
3577: /* Don't delay on first loop */
3578: if(first_cycle)
3579: first_cycle=FALSE;
3580: else
3581: sem_trywait_block(&sendmail_wakeup_sem,startup->sem_chk_freq*1000);
3582:
3583: sprintf(smb.file,"%smail",scfg.data_dir);
3584: smb.retry_time=scfg.smb_retry_time;
3585: smb.subnum=INVALID_SUB;
3586: if((i=smb_open(&smb))!=SMB_SUCCESS)
3587: continue;
3588: if((i=smb_locksmbhdr(&smb))!=SMB_SUCCESS)
3589: continue;
3590: i=smb_getstatus(&smb);
3591: smb_unlocksmbhdr(&smb);
3592: if(i!=0)
3593: continue;
3594: if(smb.status.last_msg==last_msg && time(NULL)-last_scan<startup->rescan_frequency)
3595: continue;
3596: last_msg=smb.status.last_msg;
3597: last_scan=time(NULL);
3598: mail=loadmail(&smb,&msgs,/* to network */0,MAIL_YOUR,0);
3599: for(l=0; l<msgs; l++) {
3600: if(active_sendmail!=0)
3601: active_sendmail=0, update_clients();
3602:
3603: if(server_socket==INVALID_SOCKET || terminate_sendmail) /* server stopped */
3604: break;
3605:
3606: if(sock!=INVALID_SOCKET) {
3607: mail_close_socket(sock);
3608: sock=INVALID_SOCKET;
3609: }
3610:
3611: if(msgtxt!=NULL) {
3612: smb_freemsgtxt(msgtxt);
3613: msgtxt=NULL;
3614: }
3615:
3616: smb_freemsgmem(&msg);
3617:
3618: msg.hdr.number=mail[l].number;
3619: if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
3620: lprintf(LOG_ERR,"0000 !SEND ERROR %d (%s) getting message index #%lu"
3621: ,i, smb.last_error, mail[l].number);
3622: break;
3623: }
3624: if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS) {
3625: lprintf(LOG_WARNING,"0000 !SEND ERROR %d (%s) locking message header #%lu"
3626: ,i, smb.last_error, msg.idx.number);
3627: continue;
3628: }
3629: if((i=smb_getmsghdr(&smb,&msg))!=SMB_SUCCESS) {
3630: smb_unlockmsghdr(&smb,&msg);
3631: lprintf(LOG_ERR,"0000 !SEND ERROR %d (%s) reading message header #%lu"
3632: ,i, smb.last_error, msg.idx.number);
3633: continue;
3634: }
3635: if(msg.hdr.attr&MSG_DELETE || msg.to_net.type!=NET_INTERNET || msg.to_net.addr==NULL) {
3636: smb_unlockmsghdr(&smb,&msg);
3637: continue;
3638: }
3639:
3640: if(!(startup->options&MAIL_OPT_SEND_INTRANSIT) && msg.hdr.netattr&MSG_INTRANSIT) {
3641: smb_unlockmsghdr(&smb,&msg);
3642: lprintf(LOG_ERR,"0000 SEND Message #%lu from %s to %s - in transit"
3643: ,msg.hdr.number, msg.from, msg.to_net.addr);
3644: continue;
3645: }
3646: msg.hdr.netattr|=MSG_INTRANSIT; /* Prevent another sendmail thread from sending this msg */
3647: smb_putmsghdr(&smb,&msg);
3648: smb_unlockmsghdr(&smb,&msg);
3649:
3650: active_sendmail=1, update_clients();
3651:
3652: lprintf(LOG_INFO,"0000 SEND Message #%lu from %s to %s"
3653: ,msg.hdr.number, msg.from, msg.to_net.addr);
3654: status("Sending");
3655: #ifdef _WIN32
3656: if(startup->outbound_sound[0] && !(startup->options&MAIL_OPT_MUTE))
3657: PlaySound(startup->outbound_sound, NULL, SND_ASYNC|SND_FILENAME);
3658: #endif
3659:
3660: lprintf(LOG_DEBUG,"0000 SEND getting message text");
3661: if((msgtxt=smb_getmsgtxt(&smb,&msg,GETMSGTXT_ALL))==NULL) {
3662: remove_msg_intransit(&smb,&msg);
3663: lprintf(LOG_ERR,"0000 !SEND ERROR (%s) retrieving message text",smb.last_error);
3664: continue;
3665: }
3666:
3667: port=0;
3668:
3669: /* Check if this is a local email ToDo */
3670: SAFECOPY(to,(char*)msg.to_net.addr);
3671: truncstr(to,"> ");
3672:
3673: p=strrchr(to,'@');
3674: if(p==NULL) {
3675: remove_msg_intransit(&smb,&msg);
3676: lprintf(LOG_WARNING,"0000 !SEND INVALID destination address: %s", to);
3677: SAFEPRINTF(err,"Invalid destination address: %s", to);
3678: bounce(&smb,&msg,err,TRUE);
3679: continue;
3680: }
3681: p++;
3682: sprintf(domain_list,"%sdomains.cfg",scfg.ctrl_dir);
3683: if(stricmp(p,scfg.sys_inetaddr)==0
3684: || stricmp(p,startup->host_name)==0
3685: || findstr(p,domain_list)) {
3686: /* This is a local message... no need to send to remote */
3687: port = startup->smtp_port;
3688: if(startup->interface_addr==0)
3689: server="127.0.0.1";
3690: else {
3691: sprintf(numeric_ip, "%u.%u.%u.%u"
3692: , startup->interface_addr >> 24
3693: , (startup->interface_addr >> 16) & 0xff
3694: , (startup->interface_addr >> 8) & 0xff
3695: , startup->interface_addr & 0xff);
3696: server = numeric_ip;
3697: }
3698: sending_locally=TRUE;
3699: }
3700: else {
3701: if(startup->options&MAIL_OPT_RELAY_TX) {
3702: server=startup->relay_server;
3703: port=startup->relay_port;
3704: } else {
3705: server=p;
3706: tp=strrchr(p,':'); /* non-standard SMTP port */
3707: if(tp!=NULL) {
3708: *tp=0;
3709: port=atoi(tp+1);
3710: }
3711: if(port==0) { /* No port specified, use MX look-up */
3712: get_dns_server(dns_server,sizeof(dns_server));
3713: if((dns=resolve_ip(dns_server))==INADDR_NONE) {
3714: remove_msg_intransit(&smb,&msg);
3715: lprintf(LOG_WARNING,"0000 !SEND INVALID DNS server address: %s"
3716: ,dns_server);
3717: continue;
3718: }
3719: lprintf(LOG_DEBUG,"0000 SEND getting MX records for %s from %s",p,dns_server);
3720: if((i=dns_getmx(p, mx, mx2, startup->interface_addr, dns
3721: ,startup->options&MAIL_OPT_USE_TCP_DNS ? TRUE : FALSE
3722: ,TIMEOUT_THREAD_WAIT/2))!=0) {
3723: remove_msg_intransit(&smb,&msg);
3724: lprintf(LOG_WARNING,"0000 !SEND ERROR %d obtaining MX records for %s from %s"
3725: ,i,p,startup->dns_server);
3726: SAFEPRINTF2(err,"Error %d obtaining MX record for %s",i,p);
3727: bounce(&smb,&msg,err,FALSE);
3728: continue;
3729: }
3730: server=mx;
3731: }
3732: }
3733: }
3734: if(!port)
3735: port=IPPORT_SMTP;
3736:
3737: if((sock=mail_open_socket(SOCK_STREAM,"smtp|sendmail"))==INVALID_SOCKET) {
3738: remove_msg_intransit(&smb,&msg);
3739: lprintf(LOG_ERR,"0000 !SEND ERROR %d opening socket", ERROR_VALUE);
3740: continue;
3741: }
3742:
3743: memset(&addr,0,sizeof(addr));
3744: addr.sin_addr.s_addr = htonl(startup->interface_addr);
3745: addr.sin_family = AF_INET;
3746:
3747: if(startup->seteuid!=NULL)
3748: startup->seteuid(FALSE);
3749: i=bind(sock,(struct sockaddr *)&addr, sizeof(addr));
3750: if(startup->seteuid!=NULL)
3751: startup->seteuid(TRUE);
3752: if(i!=0) {
3753: remove_msg_intransit(&smb,&msg);
3754: lprintf(LOG_ERR,"%04d !SEND ERROR %d (%d) binding socket", sock, i, ERROR_VALUE);
3755: continue;
3756: }
3757:
3758: strcpy(err,"UNKNOWN ERROR");
3759: success=FALSE;
3760: for(j=0;j<2 && !success;j++) {
3761: if(j) {
3762: if(startup->options&MAIL_OPT_RELAY_TX || !mx2[0])
3763: break;
3764: server=mx2; /* Give second mx record a try */
3765: }
3766:
3767: lprintf(LOG_DEBUG,"%04d SEND resolving SMTP hostname: %s", sock, server);
3768: ip_addr=resolve_ip(server);
3769: if(ip_addr==INADDR_NONE) {
3770: SAFEPRINTF(err,"Failed to resolve SMTP hostname: %s",server);
3771: continue;
3772: }
3773:
3774: memset(&server_addr,0,sizeof(server_addr));
3775: server_addr.sin_addr.s_addr = ip_addr;
3776: server_addr.sin_family = AF_INET;
3777: server_addr.sin_port = htons(port);
3778:
3779: if((server==mx || server==mx2)
3780: && ((ip_addr&0xff)==127 || ip_addr==0)) {
3781: SAFEPRINTF2(err,"Bad IP address (%s) for MX server: %s"
3782: ,inet_ntoa(server_addr.sin_addr),server);
3783: continue;
3784: }
3785:
3786: lprintf(LOG_INFO,"%04d SEND connecting to port %u on %s [%s]"
3787: ,sock
3788: ,ntohs(server_addr.sin_port)
3789: ,server,inet_ntoa(server_addr.sin_addr));
3790: if((i=connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)))!=0) {
3791: i=ERROR_VALUE;
3792: lprintf(LOG_WARNING,"%04d !SEND ERROR %d connecting to SMTP server: %s"
3793: ,sock
3794: ,i, server);
3795: SAFEPRINTF2(err,"Error %d connecting to SMTP server: %s"
3796: ,i, server);
3797: continue;
3798: }
3799: success=TRUE;
3800: }
3801: if(!success) { /* Failed to send, so bounce */
3802: remove_msg_intransit(&smb,&msg);
3803: bounce(&smb,&msg,err,FALSE);
3804: continue;
3805: }
3806:
3807: lprintf(LOG_DEBUG,"%04d SEND connected to %s",sock,server);
3808:
3809: /* HELO */
3810: if(!sockgetrsp(sock,"220",buf,sizeof(buf))) {
3811: remove_msg_intransit(&smb,&msg);
3812: SAFEPRINTF3(err,badrsp_err,server,buf,"220");
3813: bounce(&smb,&msg,err,buf[0]=='5');
3814: continue;
3815: }
3816: if(startup->options&MAIL_OPT_RELAY_TX
3817: && (startup->options&MAIL_OPT_RELAY_AUTH_MASK)!=0) /* Requires ESMTP */
3818: sockprintf(sock,"EHLO %s",startup->host_name);
3819: else
3820: sockprintf(sock,"HELO %s",startup->host_name);
3821: if(!sockgetrsp(sock,"250", buf, sizeof(buf))) {
3822: remove_msg_intransit(&smb,&msg);
3823: SAFEPRINTF3(err,badrsp_err,server,buf,"250");
3824: bounce(&smb,&msg,err,buf[0]=='5');
3825: continue;
3826: }
3827:
3828: /* AUTH */
3829: if(startup->options&MAIL_OPT_RELAY_TX
3830: && (startup->options&MAIL_OPT_RELAY_AUTH_MASK)!=0 && !sending_locally) {
3831: switch(startup->options&MAIL_OPT_RELAY_AUTH_MASK) {
3832: case MAIL_OPT_RELAY_AUTH_PLAIN:
3833: p="PLAIN";
3834: break;
3835: case MAIL_OPT_RELAY_AUTH_LOGIN:
3836: p="LOGIN";
3837: break;
3838: case MAIL_OPT_RELAY_AUTH_CRAM_MD5:
3839: p="CRAM-MD5";
3840: break;
3841: default:
3842: p="<unknown>";
3843: break;
3844: }
3845: sockprintf(sock,"AUTH %s",p);
3846: if(!sockgetrsp(sock,"334",buf,sizeof(buf))) {
3847: SAFEPRINTF3(err,badrsp_err,server,buf,"334 Username/Challenge");
3848: bounce(&smb,&msg,err,buf[0]=='5');
3849: continue;
3850: }
3851: switch(startup->options&MAIL_OPT_RELAY_AUTH_MASK) {
3852: case MAIL_OPT_RELAY_AUTH_PLAIN:
3853: p=startup->relay_user;
3854: break;
3855: case MAIL_OPT_RELAY_AUTH_LOGIN:
3856: b64_encode(p=resp,sizeof(resp),startup->relay_user,0);
3857: break;
3858: case MAIL_OPT_RELAY_AUTH_CRAM_MD5:
3859: p=buf;
3860: FIND_WHITESPACE(p);
3861: SKIP_WHITESPACE(p);
3862: b64_decode(challenge,sizeof(challenge),p,0);
3863:
3864: /* Calculate response */
3865: memset(secret,0,sizeof(secret));
3866: SAFECOPY(secret,startup->relay_pass);
3867: for(i=0;i<sizeof(secret);i++)
3868: md5_data[i]=secret[i]^0x36; /* ipad */
3869: strcpy(md5_data+i,challenge);
3870: MD5_calc(digest,md5_data,sizeof(secret)+strlen(challenge));
3871: for(i=0;i<sizeof(secret);i++)
3872: md5_data[i]=secret[i]^0x5c; /* opad */
3873: memcpy(md5_data+i,digest,sizeof(digest));
3874: MD5_calc(digest,md5_data,sizeof(secret)+sizeof(digest));
3875:
3876: safe_snprintf(buf,sizeof(buf),"%s %s",startup->relay_user,MD5_hex(str,digest));
3877: b64_encode(p=resp,sizeof(resp),buf,0);
3878: break;
3879: default:
3880: p="<unknown>";
3881: break;
3882: }
3883: sockprintf(sock,"%s",p);
3884: if((startup->options&MAIL_OPT_RELAY_AUTH_MASK)!=MAIL_OPT_RELAY_AUTH_CRAM_MD5) {
3885: if(!sockgetrsp(sock,"334",buf,sizeof(buf))) {
3886: SAFEPRINTF3(err,badrsp_err,server,buf,"334 Password");
3887: bounce(&smb,&msg,err,buf[0]=='5');
3888: continue;
3889: }
3890: switch(startup->options&MAIL_OPT_RELAY_AUTH_MASK) {
3891: case MAIL_OPT_RELAY_AUTH_PLAIN:
3892: p=startup->relay_pass;
3893: break;
3894: case MAIL_OPT_RELAY_AUTH_LOGIN:
3895: b64_encode(p=buf,sizeof(buf),startup->relay_pass,0);
3896: break;
3897: default:
3898: p="<unknown>";
3899: break;
3900: }
3901: sockprintf(sock,"%s",p);
3902: }
3903: if(!sockgetrsp(sock,"235",buf,sizeof(buf))) {
3904: SAFEPRINTF3(err,badrsp_err,server,buf,"235");
3905: bounce(&smb,&msg,err,buf[0]=='5');
3906: continue;
3907: }
3908: }
3909:
3910: /* MAIL */
3911: if(msg.from_net.type==NET_INTERNET && msg.reverse_path!=NULL)
3912: SAFECOPY(fromaddr,msg.reverse_path);
3913: else
3914: usermailaddr(&scfg,fromaddr,msg.from);
3915: truncstr(fromaddr," ");
3916: if(fromaddr[0]=='<')
3917: sockprintf(sock,"MAIL FROM: %s",fromaddr);
3918: else
3919: sockprintf(sock,"MAIL FROM: <%s>",fromaddr);
3920: if(!sockgetrsp(sock,"250", buf, sizeof(buf))) {
3921: remove_msg_intransit(&smb,&msg);
3922: SAFEPRINTF3(err,badrsp_err,server,buf,"250");
3923: bounce(&smb,&msg,err,buf[0]=='5');
3924: continue;
3925: }
3926: /* RCPT */
3927: if(msg.forward_path!=NULL) {
3928: SAFECOPY(toaddr,msg.forward_path);
3929: } else {
3930: if((p=strrchr((char*)msg.to_net.addr,'<'))!=NULL)
3931: p++;
3932: else
3933: p=(char*)msg.to_net.addr;
3934: SAFECOPY(toaddr,p);
3935: truncstr(toaddr,"> ");
3936: if((p=strrchr(toaddr,'@'))!=NULL && (tp=strrchr(toaddr,':'))!=NULL
3937: && tp > p)
3938: *tp=0; /* Remove ":port" designation from envelope */
3939: }
3940: sockprintf(sock,"RCPT TO: <%s>", toaddr);
3941: if(!sockgetrsp(sock,"25", buf, sizeof(buf))) {
3942: remove_msg_intransit(&smb,&msg);
3943: SAFEPRINTF3(err,badrsp_err,server,buf,"25*");
3944: bounce(&smb,&msg,err,buf[0]=='5');
3945: continue;
3946: }
3947: /* DATA */
3948: sockprintf(sock,"DATA");
3949: if(!sockgetrsp(sock,"354", buf, sizeof(buf))) {
3950: remove_msg_intransit(&smb,&msg);
3951: SAFEPRINTF3(err,badrsp_err,server,buf,"354");
3952: bounce(&smb,&msg,err,buf[0]=='5');
3953: continue;
3954: }
3955: lprintf(LOG_DEBUG,"%04d SEND sending message text (%u bytes)"
3956: ,sock, strlen(msgtxt));
3957: lines=sockmsgtxt(sock,&msg,msgtxt,-1);
3958: if(!sockgetrsp(sock,"250", buf, sizeof(buf))) {
3959: remove_msg_intransit(&smb,&msg);
3960: SAFEPRINTF3(err,badrsp_err,server,buf,"250");
3961: bounce(&smb,&msg,err,buf[0]=='5');
3962: continue;
3963: }
3964: lprintf(LOG_DEBUG,"%04d SEND message transfer complete (%lu lines)", sock, lines);
3965:
3966: /* Now lets mark this message for deletion without corrupting the index */
3967: msg.hdr.attr|=MSG_DELETE;
3968: msg.hdr.netattr&=~MSG_INTRANSIT;
3969: if((i=smb_updatemsg(&smb,&msg))!=SMB_SUCCESS)
3970: lprintf(LOG_ERR,"%04d !SEND ERROR %d (%s) deleting message #%lu"
3971: ,sock, i, smb.last_error, msg.hdr.number);
3972: if(msg.hdr.auxattr&MSG_FILEATTACH)
3973: delfattach(&scfg,&msg);
3974:
3975: /* QUIT */
3976: sockprintf(sock,"QUIT");
3977: sockgetrsp(sock,"221", buf, sizeof(buf));
3978: mail_close_socket(sock);
3979: sock=INVALID_SOCKET;
3980: }
3981: status(STATUS_WFC);
3982: /* Free up resources here */
3983: if(mail!=NULL)
3984: freemail(mail);
3985: }
3986: if(sock!=INVALID_SOCKET)
3987: mail_close_socket(sock);
3988:
3989: smb_freemsgtxt(msgtxt);
3990: smb_freemsgmem(&msg);
3991: smb_close(&smb);
3992:
3993: if(active_sendmail!=0)
3994: active_sendmail=0, update_clients();
3995:
3996: thread_down();
3997: lprintf(LOG_DEBUG,"0000 SendMail thread terminated (%u threads remain)", thread_count);
3998:
3999: sendmail_running=FALSE;
4000: }
4001:
4002: void DLLCALL mail_terminate(void)
4003: {
4004: lprintf(LOG_DEBUG,"%04d Mail Server terminate",server_socket);
4005: terminate_server=TRUE;
4006: }
4007:
4008: static void cleanup(int code)
4009: {
4010: int i;
4011:
4012: free_cfg(&scfg);
4013:
4014: semfile_list_free(&recycle_semfiles);
4015: semfile_list_free(&shutdown_semfiles);
4016:
4017: if(mailproc_list!=NULL) {
4018: for(i=0;i<mailproc_count;i++)
4019: strListFree(&mailproc_list[i].to);
4020: FREE_AND_NULL(mailproc_list);
4021: }
4022:
4023: if(server_socket!=INVALID_SOCKET) {
4024: mail_close_socket(server_socket);
4025: server_socket=INVALID_SOCKET;
4026: }
4027:
4028: if(pop3_socket!=INVALID_SOCKET) {
4029: mail_close_socket(pop3_socket);
4030: pop3_socket=INVALID_SOCKET;
4031: }
4032:
4033: update_clients();
4034:
4035: #ifdef _WINSOCKAPI_
4036: if(WSAInitialized && WSACleanup()!=0)
4037: lprintf(LOG_ERR,"0000 !WSACleanup ERROR %d",ERROR_VALUE);
4038: #endif
4039:
4040: thread_down();
4041: status("Down");
4042: if(terminate_server || code)
4043: lprintf(LOG_INFO,"#### Mail Server thread terminated (%u threads remain, %lu clients served)"
4044: ,thread_count, served);
4045: if(startup!=NULL && startup->terminated!=NULL)
4046: startup->terminated(startup->cbdata,code);
4047: }
4048:
4049: const char* DLLCALL mail_ver(void)
4050: {
4051: static char ver[256];
4052: char compiler[32];
4053:
4054: DESCRIBE_COMPILER(compiler);
4055:
4056: sscanf("$Revision: 1.412 $", "%*s %s", revision);
4057:
4058: sprintf(ver,"Synchronet Mail Server %s%s SMBLIB %s "
4059: "Compiled %s %s with %s"
4060: ,revision
4061: #ifdef _DEBUG
4062: ," Debug"
4063: #else
4064: ,""
4065: #endif
4066: ,smb_lib_ver()
4067: ,__DATE__, __TIME__, compiler
4068: );
4069:
4070: return(ver);
4071: }
4072:
4073: void DLLCALL mail_server(void* arg)
4074: {
4075: char* p;
4076: char path[MAX_PATH+1];
4077: char str[256];
4078: char error[256];
4079: char compiler[32];
4080: SOCKADDR_IN server_addr;
4081: SOCKADDR_IN client_addr;
4082: socklen_t client_addr_len;
4083: SOCKET client_socket;
4084: int i;
4085: int result;
4086: ulong l;
4087: time_t t;
4088: time_t start;
4089: time_t initialized=0;
4090: fd_set socket_set;
4091: SOCKET high_socket_set;
4092: pop3_t* pop3;
4093: smtp_t* smtp;
4094: struct timeval tv;
4095: FILE* fp;
4096: str_list_t sec_list;
4097:
4098: mail_ver();
4099:
4100: startup=(mail_startup_t*)arg;
4101:
4102: #ifdef _THREAD_SUID_BROKEN
4103: if(thread_suid_broken)
4104: startup->seteuid(TRUE);
4105: #endif
4106:
4107: if(startup==NULL) {
4108: sbbs_beep(100,500);
4109: fprintf(stderr, "No startup structure passed!\n");
4110: return;
4111: }
4112:
4113: if(startup->size!=sizeof(mail_startup_t)) { /* verify size */
4114: sbbs_beep(100,500);
4115: sbbs_beep(300,500);
4116: sbbs_beep(100,500);
4117: fprintf(stderr, "Invalid startup structure!\n");
4118: return;
4119: }
4120:
4121: /* Setup intelligent defaults */
4122: if(startup->relay_port==0) startup->relay_port=IPPORT_SMTP;
4123: if(startup->smtp_port==0) startup->smtp_port=IPPORT_SMTP;
4124: if(startup->pop3_port==0) startup->pop3_port=IPPORT_POP3;
4125: if(startup->rescan_frequency==0) startup->rescan_frequency=3600; /* 60 minutes */
4126: if(startup->max_delivery_attempts==0) startup->max_delivery_attempts=50;
4127: if(startup->max_inactivity==0) startup->max_inactivity=120; /* seconds */
4128: if(startup->max_recipients==0) startup->max_recipients=100;
4129: if(startup->sem_chk_freq==0) startup->sem_chk_freq=2;
4130:
4131: #ifdef JAVASCRIPT
4132: if(startup->js.max_bytes==0) startup->js.max_bytes=JAVASCRIPT_MAX_BYTES;
4133: if(startup->js.cx_stack==0) startup->js.cx_stack=JAVASCRIPT_CONTEXT_STACK;
4134: #endif
4135:
4136: uptime=0;
4137: served=0;
4138: startup->recycle_now=FALSE;
4139: startup->shutdown_now=FALSE;
4140: terminate_server=FALSE;
4141:
4142: SetThreadName("Mail Server");
4143:
4144: do {
4145:
4146: thread_up(FALSE /* setuid */);
4147:
4148: status("Initializing");
4149:
4150: memset(&scfg, 0, sizeof(scfg));
4151:
4152: lprintf(LOG_INFO,"Synchronet Mail Server Revision %s%s"
4153: ,revision
4154: #ifdef _DEBUG
4155: ," Debug"
4156: #else
4157: ,""
4158: #endif
4159: );
4160:
4161: DESCRIBE_COMPILER(compiler);
4162:
4163: lprintf(LOG_INFO,"Compiled %s %s with %s", __DATE__, __TIME__, compiler);
4164:
4165: lprintf(LOG_INFO,"SMBLIB %s (format %x.%02x)",smb_lib_ver(),smb_ver()>>8,smb_ver()&0xff);
4166:
4167: sbbs_srand();
4168:
4169: if(!winsock_startup()) {
4170: cleanup(1);
4171: return;
4172: }
4173:
4174: t=time(NULL);
4175: lprintf(LOG_INFO,"Initializing on %.24s with options: %lx"
4176: ,CTIME_R(&t,str),startup->options);
4177:
4178: /* Initial configuration and load from CNF files */
4179: SAFECOPY(scfg.ctrl_dir,startup->ctrl_dir);
4180: lprintf(LOG_INFO,"Loading configuration files from %s", scfg.ctrl_dir);
4181: scfg.size=sizeof(scfg);
4182: SAFECOPY(error,UNKNOWN_LOAD_ERROR);
4183: if(!load_cfg(&scfg, NULL, TRUE, error)) {
4184: lprintf(LOG_ERR,"!ERROR %s",error);
4185: lprintf(LOG_ERR,"!Failed to load configuration files");
4186: cleanup(1);
4187: return;
4188: }
4189:
4190: if(startup->temp_dir[0])
4191: SAFECOPY(scfg.temp_dir,startup->temp_dir);
4192: else
4193: SAFECOPY(scfg.temp_dir,"../temp");
4194: prep_dir(scfg.ctrl_dir, scfg.temp_dir, sizeof(scfg.temp_dir));
4195: MKDIR(scfg.temp_dir);
4196: lprintf(LOG_DEBUG,"Temporary file directory: %s", scfg.temp_dir);
4197: if(!isdir(scfg.temp_dir)) {
4198: lprintf(LOG_ERR,"!Invalid temp directory: %s", scfg.temp_dir);
4199: cleanup(1);
4200: return;
4201: }
4202:
4203: /* Parse the mailproc[.host].ini */
4204: mailproc_list=NULL;
4205: mailproc_count=0;
4206: iniFileName(path,sizeof(path),scfg.ctrl_dir,"mailproc.ini");
4207: if((fp=iniOpenFile(path, /* create? */FALSE))!=NULL) {
4208: lprintf(LOG_DEBUG,"Reading %s",path);
4209: sec_list = iniReadSectionList(fp,/* prefix */NULL);
4210: if((mailproc_count=strListCount(sec_list))!=0
4211: && (mailproc_list=malloc(mailproc_count*sizeof(struct mailproc)))!=NULL) {
4212: for(i=0;i<mailproc_count;i++) {
4213: memset(&mailproc_list[i],0,sizeof(struct mailproc));
4214: SAFECOPY(mailproc_list[i].cmdline,sec_list[i]);
4215: mailproc_list[i].to =
4216: iniReadStringList(fp,sec_list[i],"to",",",NULL);
4217: mailproc_list[i].passthru =
4218: iniReadBool(fp,sec_list[i],"passthru",TRUE);
4219: mailproc_list[i].native =
4220: iniReadBool(fp,sec_list[i],"native",FALSE);
4221: }
4222: }
4223: iniFreeStringList(sec_list);
4224: iniCloseFile(fp);
4225: }
4226:
4227: if(startup->host_name[0]==0)
4228: SAFECOPY(startup->host_name,scfg.sys_inetaddr);
4229:
4230: if(!(scfg.sys_misc&SM_LOCAL_TZ) && !(startup->options&MAIL_OPT_LOCAL_TIMEZONE)) {
4231: if(putenv("TZ=UTC0"))
4232: lprintf(LOG_ERR,"!putenv() FAILED");
4233: tzset();
4234:
4235: if((t=checktime())!=0) { /* Check binary time */
4236: lprintf(LOG_ERR,"!TIME PROBLEM (%ld)",t);
4237: cleanup(1);
4238: return;
4239: }
4240: }
4241:
4242: if(uptime==0)
4243: uptime=time(NULL); /* this must be done *after* setting the timezone */
4244:
4245: if(startup->max_clients==0) {
4246: startup->max_clients=scfg.sys_nodes;
4247: if(startup->max_clients<10)
4248: startup->max_clients=10;
4249: }
4250:
4251: lprintf(LOG_DEBUG,"Maximum clients: %u",startup->max_clients);
4252:
4253: lprintf(LOG_DEBUG,"Maximum inactivity: %u seconds",startup->max_inactivity);
4254:
4255: active_clients=0,update_clients();
4256:
4257: /* open a socket and wait for a client */
4258:
4259: server_socket = mail_open_socket(SOCK_STREAM,"smtp");
4260:
4261: if(server_socket == INVALID_SOCKET) {
4262: lprintf(LOG_ERR,"!ERROR %d opening socket", ERROR_VALUE);
4263: cleanup(1);
4264: return;
4265: }
4266:
4267: lprintf(LOG_DEBUG,"%04d SMTP socket opened",server_socket);
4268:
4269: /*****************************/
4270: /* Listen for incoming calls */
4271: /*****************************/
4272: memset(&server_addr, 0, sizeof(server_addr));
4273:
4274: server_addr.sin_addr.s_addr = htonl(startup->interface_addr);
4275: server_addr.sin_family = AF_INET;
4276: server_addr.sin_port = htons(startup->smtp_port);
4277:
4278: if(startup->seteuid!=NULL)
4279: startup->seteuid(FALSE);
4280: result = retry_bind(server_socket,(struct sockaddr *)&server_addr,sizeof(server_addr)
4281: ,startup->bind_retry_count,startup->bind_retry_delay,"SMTP Server",lprintf);
4282: if(startup->seteuid!=NULL)
4283: startup->seteuid(TRUE);
4284: if(result != 0) {
4285: lprintf(LOG_ERR,"%04d %s",server_socket, BIND_FAILURE_HELP);
4286: cleanup(1);
4287: return;
4288: }
4289:
4290: lprintf(LOG_DEBUG,"%04d SMTP socket bound to port %u"
4291: ,server_socket, startup->smtp_port);
4292:
4293: result = listen (server_socket, 1);
4294:
4295: if(result != 0) {
4296: lprintf(LOG_ERR,"%04d !ERROR %d (%d) listening on socket"
4297: ,server_socket, result, ERROR_VALUE);
4298: cleanup(1);
4299: return;
4300: }
4301:
4302: if(startup->options&MAIL_OPT_ALLOW_POP3) {
4303:
4304: /* open a socket and wait for a client */
4305:
4306: pop3_socket = mail_open_socket(SOCK_STREAM,"pop3");
4307:
4308: if(pop3_socket == INVALID_SOCKET) {
4309: lprintf(LOG_ERR,"!ERROR %d opening POP3 socket", ERROR_VALUE);
4310: cleanup(1);
4311: return;
4312: }
4313:
4314: lprintf(LOG_DEBUG,"%04d POP3 socket opened",pop3_socket);
4315:
4316: /*****************************/
4317: /* Listen for incoming calls */
4318: /*****************************/
4319: memset(&server_addr, 0, sizeof(server_addr));
4320:
4321: server_addr.sin_addr.s_addr = htonl(startup->interface_addr);
4322: server_addr.sin_family = AF_INET;
4323: server_addr.sin_port = htons(startup->pop3_port);
4324:
4325: if(startup->seteuid!=NULL)
4326: startup->seteuid(FALSE);
4327: result = retry_bind(pop3_socket,(struct sockaddr *)&server_addr,sizeof(server_addr)
4328: ,startup->bind_retry_count,startup->bind_retry_delay,"POP3 Server",lprintf);
4329: if(startup->seteuid!=NULL)
4330: startup->seteuid(TRUE);
4331: if(result != 0) {
4332: lprintf(LOG_ERR,"%04d %s",pop3_socket,BIND_FAILURE_HELP);
4333: cleanup(1);
4334: return;
4335: }
4336:
4337: lprintf(LOG_DEBUG,"%04d POP3 socket bound to port %u"
4338: ,pop3_socket, startup->pop3_port);
4339:
4340: result = listen (pop3_socket, 1);
4341:
4342: if(result != 0) {
4343: lprintf(LOG_ERR,"%04d !ERROR %d (%d) listening on POP3 socket"
4344: ,pop3_socket, result, ERROR_VALUE);
4345: cleanup(1);
4346: return;
4347: }
4348: }
4349:
4350: sem_init(&sendmail_wakeup_sem,0,0);
4351:
4352: if(!(startup->options&MAIL_OPT_NO_SENDMAIL))
4353: _beginthread(sendmail_thread, 0, NULL);
4354:
4355: lprintf(LOG_NOTICE,"%04d Mail Server thread started",server_socket);
4356: status(STATUS_WFC);
4357:
4358: /* Setup recycle/shutdown semaphore file lists */
4359: shutdown_semfiles=semfile_list_init(scfg.ctrl_dir,"shutdown","mail");
4360: recycle_semfiles=semfile_list_init(scfg.ctrl_dir,"recycle","mail");
4361: SAFEPRINTF(path,"%smailsrvr.rec",scfg.ctrl_dir); /* legacy */
4362: semfile_list_add(&recycle_semfiles,path);
4363: if(!initialized) {
4364: initialized=time(NULL);
4365: semfile_list_check(&initialized,recycle_semfiles);
4366: semfile_list_check(&initialized,shutdown_semfiles);
4367: }
4368:
4369: /* signal caller that we've started up successfully */
4370: if(startup->started!=NULL)
4371: startup->started(startup->cbdata);
4372:
4373: while(server_socket!=INVALID_SOCKET && !terminate_server) {
4374:
4375: if(active_clients==0) {
4376: if(!(startup->options&MAIL_OPT_NO_RECYCLE)) {
4377: if((p=semfile_list_check(&initialized,recycle_semfiles))!=NULL) {
4378: lprintf(LOG_INFO,"%04d Recycle semaphore file (%s) detected"
4379: ,server_socket,p);
4380: break;
4381: }
4382: #if 0 /* unused */
4383: if(startup->recycle_sem!=NULL && sem_trywait(&startup->recycle_sem)==0)
4384: startup->recycle_now=TRUE;
4385: #endif
4386: if(startup->recycle_now==TRUE) {
4387: lprintf(LOG_NOTICE,"%04d Recycle semaphore signaled", server_socket);
4388: startup->recycle_now=FALSE;
4389: break;
4390: }
4391: }
4392: if(((p=semfile_list_check(&initialized,shutdown_semfiles))!=NULL
4393: && lprintf(LOG_INFO,"%04d Shutdown semaphore file (%s) detected"
4394: ,server_socket,p))
4395: || (startup->shutdown_now==TRUE
4396: && lprintf(LOG_INFO,"%04d Shutdown semaphore signaled",server_socket))) {
4397: startup->shutdown_now=FALSE;
4398: terminate_server=TRUE;
4399: break;
4400: }
4401: }
4402:
4403: /* now wait for connection */
4404:
4405: FD_ZERO(&socket_set);
4406: FD_SET(server_socket,&socket_set);
4407: high_socket_set=server_socket+1;
4408: if(startup->options&MAIL_OPT_ALLOW_POP3
4409: && pop3_socket!=INVALID_SOCKET) {
4410: FD_SET(pop3_socket,&socket_set);
4411: if(pop3_socket+1>high_socket_set)
4412: high_socket_set=pop3_socket+1;
4413: }
4414:
4415: tv.tv_sec=startup->sem_chk_freq;
4416: tv.tv_usec=0;
4417:
4418: if((i=select(high_socket_set,&socket_set,NULL,NULL,&tv))<1) {
4419: if(i==0)
4420: continue;
4421: if(ERROR_VALUE==EINTR)
4422: lprintf(LOG_DEBUG,"%04d Mail Server listening interrupted",server_socket);
4423: else if(ERROR_VALUE == ENOTSOCK)
4424: lprintf(LOG_NOTICE,"%04d Mail Server sockets closed",server_socket);
4425: else
4426: lprintf(LOG_WARNING,"%04d !ERROR %d selecting sockets",server_socket,ERROR_VALUE);
4427: continue;
4428: }
4429:
4430: if(server_socket!=INVALID_SOCKET && !terminate_server
4431: && FD_ISSET(server_socket,&socket_set)) {
4432:
4433: client_addr_len = sizeof(client_addr);
4434: client_socket = accept(server_socket, (struct sockaddr *)&client_addr
4435: ,&client_addr_len);
4436:
4437: if(client_socket == INVALID_SOCKET)
4438: {
4439: #if 0 /* is this necessary still? */
4440: if(ERROR_VALUE == ENOTSOCK || ERROR_VALUE == EINVAL) {
4441: lprintf(LOG_NOTICE,"%04d SMTP socket closed while listening"
4442: ,server_socket);
4443: break;
4444: }
4445: #endif
4446: lprintf(LOG_WARNING,"%04d SMTP !ERROR %d accepting connection"
4447: ,server_socket, ERROR_VALUE);
4448: #ifdef _WIN32
4449: if(WSAGetLastError()==WSAENOBUFS) /* recycle (re-init WinSock) on this error */
4450: break;
4451: #endif
4452: continue;
4453: }
4454: if(startup->socket_open!=NULL)
4455: startup->socket_open(startup->cbdata,TRUE);
4456: sockets++;
4457:
4458: if(trashcan(&scfg,inet_ntoa(client_addr.sin_addr),"ip-silent")) {
4459: mail_close_socket(client_socket);
4460: continue;
4461: }
4462:
4463: if(active_clients>=startup->max_clients) {
4464: lprintf(LOG_WARNING,"%04d SMTP !MAXIMUM CLIENTS (%u) reached, access denied"
4465: ,client_socket, startup->max_clients);
4466: sockprintf(client_socket,"421 Maximum active clients reached, please try again later.");
4467: mswait(3000);
4468: mail_close_socket(client_socket);
4469: continue;
4470: }
4471:
4472: l=1;
4473:
4474: if((i=ioctlsocket(client_socket, FIONBIO, &l))!=0) {
4475: lprintf(LOG_ERR,"%04d SMTP !ERROR %d (%d) disabling blocking on socket"
4476: ,client_socket, i, ERROR_VALUE);
4477: mail_close_socket(client_socket);
4478: continue;
4479: }
4480:
4481: if((smtp=malloc(sizeof(smtp_t)))==NULL) {
4482: lprintf(LOG_CRIT,"%04d SMTP !ERROR allocating %u bytes of memory for smtp_t"
4483: ,client_socket, sizeof(smtp_t));
4484: mail_close_socket(client_socket);
4485: continue;
4486: }
4487:
4488: smtp->socket=client_socket;
4489: smtp->client_addr=client_addr;
4490: _beginthread (smtp_thread, 0, smtp);
4491: served++;
4492: }
4493:
4494: if(pop3_socket!=INVALID_SOCKET
4495: && FD_ISSET(pop3_socket,&socket_set)) {
4496:
4497: client_addr_len = sizeof(client_addr);
4498: client_socket = accept(pop3_socket, (struct sockaddr *)&client_addr
4499: ,&client_addr_len);
4500:
4501: if(client_socket == INVALID_SOCKET)
4502: {
4503: #if 0 /* is this necessary still? */
4504: if(ERROR_VALUE == ENOTSOCK || ERROR_VALUE == EINVAL) {
4505: lprintf(LOG_NOTICE,"%04d POP3 socket closed while listening",pop3_socket);
4506: break;
4507: }
4508: #endif
4509: lprintf(LOG_WARNING,"%04d POP3 !ERROR %d accepting connection"
4510: ,pop3_socket, ERROR_VALUE);
4511: #ifdef _WIN32
4512: if(WSAGetLastError()==WSAENOBUFS) /* recycle (re-init WinSock) on this error */
4513: break;
4514: #endif
4515: continue;
4516: }
4517: if(startup->socket_open!=NULL)
4518: startup->socket_open(startup->cbdata,TRUE);
4519: sockets++;
4520:
4521: if(trashcan(&scfg,inet_ntoa(client_addr.sin_addr),"ip-silent")) {
4522: mail_close_socket(client_socket);
4523: continue;
4524: }
4525:
4526: if(active_clients>=startup->max_clients) {
4527: lprintf(LOG_WARNING,"%04d POP3 !MAXIMUM CLIENTS (%u) reached, access denied"
4528: ,client_socket, startup->max_clients);
4529: sockprintf(client_socket,"-ERR Maximum active clients reached, please try again later.");
4530: mswait(3000);
4531: mail_close_socket(client_socket);
4532: continue;
4533: }
4534:
4535:
4536: l=1;
4537:
4538: if((i=ioctlsocket(client_socket, FIONBIO, &l))!=0) {
4539: lprintf(LOG_ERR,"%04d POP3 !ERROR %d (%d) disabling blocking on socket"
4540: ,client_socket, i, ERROR_VALUE);
4541: sockprintf(client_socket,"-ERR System error, please try again later.");
4542: mswait(3000);
4543: mail_close_socket(client_socket);
4544: continue;
4545: }
4546:
4547: if((pop3=malloc(sizeof(pop3_t)))==NULL) {
4548: lprintf(LOG_CRIT,"%04d POP3 !ERROR allocating %u bytes of memory for pop3_t"
4549: ,client_socket,sizeof(pop3_t));
4550: sockprintf(client_socket,"-ERR System error, please try again later.");
4551: mswait(3000);
4552: mail_close_socket(client_socket);
4553: continue;
4554: }
4555:
4556: pop3->socket=client_socket;
4557: pop3->client_addr=client_addr;
4558:
4559: _beginthread (pop3_thread, 0, pop3);
4560: served++;
4561: }
4562: }
4563:
4564: if(active_clients) {
4565: lprintf(LOG_DEBUG,"%04d Waiting for %d active clients to disconnect..."
4566: ,server_socket, active_clients);
4567: start=time(NULL);
4568: while(active_clients) {
4569: if(time(NULL)-start>startup->max_inactivity) {
4570: lprintf(LOG_WARNING,"%04d !TIMEOUT waiting for %d active clients"
4571: ,server_socket, active_clients);
4572: break;
4573: }
4574: mswait(100);
4575: }
4576: }
4577:
4578: if(sendmail_running) {
4579: terminate_sendmail=TRUE;
4580: sem_post(&sendmail_wakeup_sem);
4581: mswait(100);
4582: }
4583: if(sendmail_running) {
4584: lprintf(LOG_DEBUG,"%04d Waiting for SendMail thread to terminate..."
4585: ,server_socket);
4586: start=time(NULL);
4587: while(sendmail_running) {
4588: if(time(NULL)-start>TIMEOUT_THREAD_WAIT) {
4589: lprintf(LOG_WARNING,"%04d !TIMEOUT waiting for sendmail thread to terminate"
4590: ,server_socket);
4591: break;
4592: }
4593: mswait(500);
4594: }
4595: }
4596: if(!sendmail_running) {
4597: while(sem_destroy(&sendmail_wakeup_sem)==-1 && errno==EBUSY) {
4598: mswait(1);
4599: sem_post(&sendmail_wakeup_sem);
4600: }
4601: }
4602:
4603: cleanup(0);
4604:
4605: if(!terminate_server) {
4606: lprintf(LOG_INFO,"Recycling server...");
4607: mswait(2000);
4608: if(startup->recycle!=NULL)
4609: startup->recycle(startup->cbdata);
4610: }
4611:
4612: } while(!terminate_server);
4613: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.