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