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