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