Newer
Older
,socket, i, smb.last_error);
break;
}
if(msg.idx.attr&MSG_DELETE)
continue;
if((i=smb_lockmsghdr(&smb,&msg))!=0) {
lprintf("%04d !POP3 ERROR %d (%s) locking message header #%lu"
,socket, i, smb.last_error, msg.hdr.number);
break;
}
i=smb_getmsghdr(&smb,&msg);
smb_unlockmsghdr(&smb,&msg);
if(i!=0) {
smb_freemsgmem(&msg);
lprintf("%04d !POP3 ERROR %d (%s) getting message header #%lu"
,socket, i, smb.last_error, msg.hdr.number);
break;
}
if(!strnicmp(buf, "LIST",4)) {
msgbytes=0;
for(i=0;i<msg.hdr.total_dfields;i++)
if(msg.dfield[i].type==TEXT_BODY || msg.dfield[i].type==TEXT_TAIL)
msgbytes+=msg.dfield[i].length;
sockprintf(socket,"%lu %lu",l+1,msgbytes);
} else /* UIDL */
sockprintf(socket,"%lu %lu",l+1,msg.hdr.number);
smb_freemsgmem(&msg);
}
sockprintf(socket,".");
continue;
}
activity=TRUE;
if(!strnicmp(buf, "RETR ",5) || !strnicmp(buf,"TOP ",4)) {
sprintf(str,"POP3: %s", user.alias);
status(str);
lines=-1;
p=buf+4;
SKIP_WHITESPACE(p);
msgnum=atol(p);
if(!strnicmp(buf,"TOP ",4)) {
SKIP_DIGIT(p);
SKIP_WHITESPACE(p);
lines=atol(p);
}
if(msgnum<1 || msgnum>msgs) {
lprintf("%04d !POP3 %s ATTEMPTED to retrieve an INVALID message #%ld"
,socket, user.alias, msgnum);
sockprintf(socket,"-ERR no such message");
continue;
}
msg.hdr.number=mail[msgnum-1].number;
lprintf("%04d POP3 %s retrieving message #%ld"
,socket, user.alias, msg.hdr.number);
if((i=smb_getmsgidx(&smb,&msg))!=0) {
lprintf("%04d !POP3 ERROR %d (%s) getting message index"
,socket, i, smb.last_error);
sockprintf(socket,"-ERR %d getting message index",i);
continue;
}
if(msg.idx.attr&MSG_DELETE) {
lprintf("%04d !POP3 ATTEMPT to retrieve DELETED message"
,socket);
sockprintf(socket,"-ERR message deleted");
continue;
}
if((i=smb_lockmsghdr(&smb,&msg))!=0) {
lprintf("%04d !POP3 ERROR %d (%s) locking message header #%lu"
,socket, i, smb.last_error, msg.hdr.number);
sockprintf(socket,"-ERR %d locking message header",i);
continue;
}
i=smb_getmsghdr(&smb,&msg);
smb_unlockmsghdr(&smb,&msg);
if(i!=0) {
lprintf("%04d !POP3 ERROR %d (%s) getting message header #%lu"
,socket, i, smb.last_error, msg.hdr.number);
sockprintf(socket,"-ERR %d getting message header",i);
continue;
}
if((msgtxt=smb_getmsgtxt(&smb,&msg,GETMSGTXT_TAILS))==NULL) {
smb_freemsgmem(&msg);
lprintf("%04d !POP3 ERROR (%s) retrieving message %lu text"
,socket, smb.last_error, msg.hdr.number);
sockprintf(socket,"-ERR retrieving message text");
continue;
}
sockprintf(socket,"+OK message follows");
lprintf("%04d POP3 sending message text (%u bytes)"
,socket,strlen(msgtxt));
lines_sent=sockmsgtxt(socket,&msg,msgtxt,lines);
/* if(startup->options&MAIL_OPT_DEBUG_POP3) */
if(lines!=-1 && lines_sent<lines) /* could send *more* lines */
lprintf("%04d !POP3 ERROR sending message text (sent %ld of %ld lines)"
,socket,lines_sent,lines);
lprintf("%04d POP3 message transfer complete (%lu lines)"
,socket,lines_sent);
msg.hdr.attr|=MSG_READ;
msg.idx.attr=msg.hdr.attr;
msg.hdr.netattr|=MSG_SENT;
if((i=smb_lockmsghdr(&smb,&msg))!=0)
lprintf("%04d !POP3 ERROR %d (%s) locking message header #%lu"
,socket, i, smb.last_error, msg.hdr.number);
if((i=smb_putmsg(&smb,&msg))!=0)
lprintf("%04d !POP3 ERROR %d (%s) marking message #%lu as read"
,socket, i, smb.last_error, msg.hdr.number);
smb_unlockmsghdr(&smb,&msg);
}
smb_freemsgmem(&msg);
smb_freemsgtxt(msgtxt);
continue;
}
if(!strnicmp(buf, "DELE ",5)) {
p=buf+5;
SKIP_WHITESPACE(p);
msgnum=atol(p);
if(msgnum<1 || msgnum>msgs) {
lprintf("%04d !POP3 %s ATTEMPTED to delete an INVALID message #%ld"
,socket, user.alias, msgnum);
sockprintf(socket,"-ERR no such message");
continue;
}
msg.hdr.number=mail[msgnum-1].number;
lprintf("%04d POP3 %s deleting message #%ld"
,socket, user.alias, msg.hdr.number);
if((i=smb_getmsgidx(&smb,&msg))!=0) {
lprintf("%04d !POP3 ERROR %d (%s) getting message index"
,socket, i, smb.last_error);
sockprintf(socket,"-ERR %d getting message index",i);
continue;
}
if((i=smb_lockmsghdr(&smb,&msg))!=0) {
lprintf("%04d !POP3 ERROR %d (%s) locking message header #%lu"
,socket, i, smb.last_error, msg.hdr.number);
sockprintf(socket,"-ERR %d locking message header",i);
continue;
}
if((i=smb_getmsghdr(&smb,&msg))!=0) {
smb_unlockmsghdr(&smb,&msg);
lprintf("%04d !POP3 ERROR %d (%s) getting message header #%lu"
,socket, i, smb.last_error, msg.hdr.number);
sockprintf(socket,"-ERR %d getting message header",i);
continue;
}
msg.hdr.attr|=MSG_DELETE;
msg.idx.attr=msg.hdr.attr;
if((i=smb_putmsg(&smb,&msg))!=0) {
smb_unlockmsghdr(&smb,&msg);
smb_freemsgmem(&msg);
lprintf("%04d !POP3 ERROR %d (%s) marking message as read"
, socket, i, smb.last_error);
sockprintf(socket,"-ERR %d marking message for deletion",i);
continue;
}
if(msg.hdr.auxattr&MSG_FILEATTACH)
delfattach(&scfg,&msg);
smb_unlockmsghdr(&smb,&msg);
smb_freemsgmem(&msg);
sockprintf(socket,"+OK");
if(startup->options&MAIL_OPT_DEBUG_POP3)
lprintf("%04d POP3 message deleted", socket);
lprintf("%04d !POP3 UNSUPPORTED COMMAND from %s: '%s'"
,socket, user.alias, buf);
sockprintf(socket,"-ERR UNSUPPORTED COMMAND: %s",buf);
}
if(user.number)

rswindell
committed
logoutuserdat(&scfg,&user,time(NULL),client.time);
if(activity)
lprintf("%04d POP3 %s logged out from port %u on %s [%s]"
,socket, user.alias, ntohs(pop3.client_addr.sin_port), host_name, host_ip);
status(STATUS_WFC);
/* Free up resources here */
if(mail!=NULL)
freemail(mail);
smb_freemsgmem(&msg);
smb_close(&smb);
if(active_clients)
active_clients--, update_clients();
client_off(socket);
thread_down();
if(startup->options&MAIL_OPT_DEBUG_POP3)
lprintf("%04d POP3 session thread terminated (%u threads remain, %lu clients served)"
,socket, thread_count, served);
/* Must be last */
mail_close_socket(socket);
static ulong rblchk(SOCKET sock, DWORD mail_addr_n, const char* rbl_addr)
{
char name[256];
DWORD mail_addr;
HOSTENT* host;
struct in_addr dnsbl_result;
mail_addr=ntohl(mail_addr_n);
,mail_addr&0xff
,(mail_addr>>8)&0xff
,(mail_addr>>16)&0xff
,(mail_addr>>24)&0xff
,rbl_addr
);
if(startup->options&MAIL_OPT_DNSBL_DEBUG)
lprintf("%04d SMTP DNSBL query: %s",sock,name);
if((host=gethostbyname(name))==NULL)
return(0);
dnsbl_result.s_addr = *((ulong*)host->h_addr_list[0]);
lprintf("%04d SMTP DNSBL query: %s resolved to: %s"
,sock,name,inet_ntoa(dnsbl_result));
return(dnsbl_result.s_addr);
static ulong dns_blacklisted(SOCKET sock, IN_ADDR addr, char* host_name, char* list, char* dnsbl_ip)
{
char fname[MAX_PATH+1];
char str[256];
char* p;
char* tp;
FILE* fp;
ulong found=0;
sprintf(fname,"%sdnsbl_exempt.cfg",scfg.ctrl_dir);
if(findstr(inet_ntoa(addr),fname))
return(FALSE);
if(findstr(host_name,fname))
return(FALSE);
sprintf(fname,"%sdns_blacklist.cfg", scfg.ctrl_dir);
if((fp=fopen(fname,"r"))==NULL)
return(FALSE);
while(!feof(fp) && !found) {
if(fgets(str,sizeof(str),fp)==NULL)
break;
truncsp(str);
p=str;
SKIP_WHITESPACE(p);
if(*p==';' || *p==0) /* comment or blank line */
continue;
sprintf(list,"%.100s",p);
/* terminate */
tp = p;
FIND_WHITESPACE(tp);
*tp=0;
found = rblchk(sock, addr.s_addr, p);
}
fclose(fp);
if(found)
strcpy(dnsbl_ip, inet_ntoa(addr));
return(found);
}
static BOOL chk_email_addr(SOCKET socket, char* p, char* host_name, char* host_ip
,char* to, char* from)
{
char addr[64];
char tmp[128];
SKIP_WHITESPACE(p);
truncstr(addr,">( ");
if(!trashcan(&scfg,addr,"email"))
return(TRUE);
lprintf("%04d !SMTP BLOCKED SOURCE: %s"
sprintf(tmp,"Blocked source e-mail address: %s", addr);
spamlog(&scfg, "SMTP", "REFUSED", tmp, host_name, host_ip, to, from);
sockprintf(socket, "554 Sender not allowed.");
return(FALSE);
}
{
int file;
if(scfg.smtpmail_sem[0]==0)
return; /* do nothing */
if((file=open(scfg.smtpmail_sem,O_WRONLY|O_CREAT|O_TRUNC))!=-1)
close(file);
}
/*****************************************************************************/
/* Returns command line generated from instr with %c replacments */
/*****************************************************************************/
static char* mailcmdstr(char* instr, char* msgpath, char* lstpath, char* errpath
,char* host, char* ip, uint usernum, char* cmd)
{
char str[256];
int i,j,len;
len=strlen(instr);
for(i=j=0;i<len;i++) {
if(instr[i]=='%') {
i++;
cmd[j]=0;
switch(toupper(instr[i])) {
case 'E':
strcat(cmd,errpath);
break;
case 'H':
strcat(cmd,host);
break;
case 'I':
strcat(cmd,ip);
break;
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
case 'G': /* Temp directory */
strcat(cmd,scfg.temp_dir);
break;
case 'J':
strcat(cmd,scfg.data_dir);
break;
case 'K':
strcat(cmd,scfg.ctrl_dir);
break;
case 'L':
strcat(cmd,lstpath);
break;
case 'F':
case 'M':
strcat(cmd,msgpath);
break;
case 'O': /* SysOp */
strcat(cmd,scfg.sys_op);
break;
case 'Q': /* QWK ID */
strcat(cmd,scfg.sys_id);
break;
case 'V': /* Synchronet Version */
sprintf(str,"%s%c",VERSION,REVISION);
strcat(cmd,str);
break;
case 'Z':
strcat(cmd,scfg.text_dir);
break;
case '!': /* EXEC Directory */
strcat(cmd,scfg.exec_dir);
break;
case '%': /* %% for percent sign */
strcat(cmd,"%");
break;
case '?': /* Platform */
#ifdef __OS2__
SAFECOPY(str,"OS2");
#else
SAFECOPY(str,PLATFORM_DESC);
#endif
strlwr(str);
strcat(cmd,str);
break;
case 'U': /* User number */
sprintf(str,"%u",usernum);
strcat(cmd,str);
break;
default: /* unknown specification */
break;
}
j=strlen(cmd);
}
else
cmd[j++]=instr[i];
}
cmd[j]=0;
return(cmd);
}
static int parse_header_field(char* buf, smbmsg_t* msg, ushort* type)
{
char* p;
ushort nettype;
if(buf[0]<=' ' && *type!=UNKNOWN) { /* folded header, append to previous */
p=buf;
truncsp(p);
smb_hfield_append_str(msg,*type,"\r\n");
return smb_hfield_append_str(msg, *type, p);
}
if(!strnicmp(buf, "TO:",3)) {
p=buf+3;
SKIP_WHITESPACE(p);
truncsp(p);
return smb_hfield_str(msg, *type=RFC822TO, p);
}
if(!strnicmp(buf, "REPLY-TO:",9)) {
p=buf+9;
SKIP_WHITESPACE(p);
truncsp(p);
smb_hfield_str(msg, *type=RFC822REPLYTO, p);
if(*p=='<') {
p++;
truncstr(p,">");
}
nettype=NET_INTERNET;
smb_hfield(msg, REPLYTONETTYPE, sizeof(nettype), &nettype);
return smb_hfield_str(msg, *type=REPLYTONETADDR, p);
}
if(!strnicmp(buf, "FROM:", 5)) {
p=buf+5;
SKIP_WHITESPACE(p);
truncsp(p);
return smb_hfield_str(msg, *type=RFC822FROM, p);
}
if(!strnicmp(buf, "ORGANIZATION:",13)) {
p=buf+13;
SKIP_WHITESPACE(p);
return smb_hfield_str(msg, *type=SENDERORG, p);
}
if(!strnicmp(buf, "DATE:",5)) {
p=buf+5;
msg->hdr.when_written=rfc822date(p);
*type=UNKNOWN;
}
if(!strnicmp(buf, "MESSAGE-ID:",11)) {
p=buf+11;
SKIP_WHITESPACE(p);
return smb_hfield_str(msg, *type=RFC822MSGID, p);
}
if(!strnicmp(buf, "IN-REPLY-TO:",12)) {
p=buf+12;
SKIP_WHITESPACE(p);
return smb_hfield_str(msg, *type=RFC822REPLYID, p);
}
/* Fall-through */
return smb_hfield_str(msg, *type=RFC822HEADER, buf);
}
static int chk_received_hdr(SOCKET socket,const char *buf,IN_ADDR *dnsbl_result, char *dnsbl, char *dnsbl_ip)
{
char host_name[128];
IN_ADDR check_addr;
char *fromstr;
char ip[16];
char *p;
char *p2;
fromstr=(char *)MALLOC(strlen(buf)+1);
if(fromstr==NULL)
return(0);
strcpy(fromstr,buf);
strlwr(fromstr);
do {
p=strstr(fromstr,"from ");
if(p==NULL)
break;
p+=4;
SKIP_WHITESPACE(p);
if(*p==0)
break;
p2=host_name;
for(;*p && !isspace(*p) && p2<host_name+126;p++) {
*p2++=*p;
}
*p2=0;
p=strtok(fromstr,"[");
if(p==NULL)
break;
p=strtok(NULL,"]");
if(p==NULL)
break;
strncpy(ip,p,16);
ip[15]=0;
check_addr.s_addr = inet_addr(ip);
if(startup->options&MAIL_OPT_DNSBL_DEBUG)
lprintf("%04d DEBUG checking %s (%s)",socket,host_name,ip);
if((dnsbl_result->s_addr=dns_blacklisted(socket,check_addr,host_name,dnsbl,dnsbl_ip))!=0)
lprintf("%04d !SMTP BLACKLISTED SERVER on %s: %s [%s] = %s"
,socket, dnsbl, host_name, ip, inet_ntoa(*dnsbl_result));
} while(0);
free(fromstr);
return(dnsbl_result->s_addr);
}
static void smtp_thread(void* arg)
{
int i;
char value[INI_MAX_VALUE_LEN];
char** sec_list;
char* section;
char buf[1024],*p,*tp,*cp;
char hdrfield[512];
char alias_buf[128];
char reverse_path[128];
char date[64];
char rcpt_name[128];
char rcpt_addr[128];

rswindell
committed
char sender[128];
char sender_addr[128];
char user_name[LEN_ALIAS+1];
char user_pass[LEN_PASS+1];
char relay_list[MAX_PATH+1];
char domain_list[MAX_PATH+1];
char spam_bait[MAX_PATH+1];
char spam_block[MAX_PATH+1];
char host_name[128];
char host_ip[64];
char dnsbl_ip[64];

rswindell
committed
char* telegram_buf;
char* msgbuf;
char challenge[256];
char response[128];
char secret[64];
char md5_data[384];
char digest[MD5_DIGEST_SIZE];
char dest_host[128];
ushort dest_port;
ushort hfield_type;
ulong hdr_lines=0;
ulong hdr_len=0;
ulong badcmds=0;

rswindell
committed
BOOL telegram=FALSE;
BOOL forward=FALSE;
BOOL no_forward=FALSE;
BOOL auth_login;
BOOL routed=FALSE;
BOOL dnsbl_recvhdr;
uint subnum=INVALID_SUB;
char msgtxt_fname[MAX_PATH+1];
char rcptlst_fname[MAX_PATH+1];
ushort rcpt_count=0;
FILE* proc_cfg;
FILE* proc_err;
char proc_err_fname[MAX_PATH+1];
char session_id[MAX_PATH+1];
FILE* spy=NULL;
SOCKET socket;
HOSTENT* host;
int smb_error;
smb_t smb;
smbmsg_t msg;
smbmsg_t newmsg;
user_t user;
user_t relay_user;

rswindell
committed
node_t node;
client_t client;
smtp_t smtp=*(smtp_t*)arg;
SOCKADDR_IN server_addr;
IN_ADDR dnsbl_result;
enum {
SMTP_STATE_INITIAL
,SMTP_STATE_HELO
,SMTP_STATE_DATA_HEADER
,SMTP_STATE_DATA_BODY
} state = SMTP_STATE_INITIAL;
enum {
SMTP_CMD_NONE
,SMTP_CMD_MAIL
,SMTP_CMD_SEND
,SMTP_CMD_SOML
,SMTP_CMD_SAML
} cmd = SMTP_CMD_NONE;
thread_up(TRUE /* setuid */);
free(arg);
socket=smtp.socket;
lprintf("%04d SMTP RX Session thread started", socket);
if(startup->inbound_sound[0] && !(startup->options&MAIL_OPT_MUTE))
PlaySound(startup->inbound_sound, NULL, SND_ASYNC|SND_FILENAME);
addr_len=sizeof(server_addr);
if((i=getsockname(socket, (struct sockaddr *)&server_addr,&addr_len))!=0) {

rswindell
committed
lprintf("%04d !SMTP ERROR %d (%d) getting address/port"
sockprintf(socket,sys_error);
mail_close_socket(socket);
thread_down();
memset(&smb,0,sizeof(smb));

rswindell
committed
memset(&msg,0,sizeof(msg));
memset(&user,0,sizeof(user));
memset(&relay_user,0,sizeof(relay_user));
SAFECOPY(host_ip,inet_ntoa(smtp.client_addr.sin_addr));
lprintf("%04d SMTP connection accepted from: %s port %u"
, socket, host_ip, ntohs(smtp.client_addr.sin_port));
if(startup->options&MAIL_OPT_NO_HOST_LOOKUP)
host=NULL;
else
host=gethostbyaddr ((char *)&smtp.client_addr.sin_addr
,sizeof(smtp.client_addr.sin_addr),AF_INET);
if(host!=NULL && host->h_name!=NULL)
else
strcpy(host_name,"<no name>");
if(!(startup->options&MAIL_OPT_NO_HOST_LOOKUP)) {
lprintf("%04d SMTP Hostname: %s", socket, host_name);
for(i=0;host!=NULL && host->h_aliases!=NULL && host->h_aliases[i]!=NULL;i++)
lprintf("%04d SMTP HostAlias: %s", socket, host->h_aliases[i]);
#if 0
if(host!=NULL) {
ip=resolve_ip(host_name);
if(ip!=smtp.client_addr.sin_addr.s_addr) {
smtp.client_addr.sin_addr.s_addr=ip;
lprintf("%04d !SMTP DNS/IP ADDRESS MISMATCH: %s vs %s"
,socket, inet_ntoa(smtp.client_addr.sin_addr), host_ip);
sockprintf(socket,"550 DNS and IP address mismatch");
mail_close_socket(socket);
thread_down();
return;
}
}
#endif
SAFECOPY(hello_name,host_name);
sprintf(spam_bait,"%sspambait.cfg",scfg.ctrl_dir);
sprintf(spam_block,"%sspamblock.cfg",scfg.ctrl_dir);
if(trashcan(&scfg,host_ip,"ip") || findstr(host_ip,spam_block)) {
lprintf("%04d !SMTP BLOCKED SERVER IP ADDRESS: %s"
,socket, host_ip);
sockprintf(socket,"550 Access denied.");

rswindell
committed
mail_close_socket(socket);
thread_down();
return;
}
if(trashcan(&scfg,host_name,"host") || findstr(host_name,spam_block)) {
lprintf("%04d !SMTP BLOCKED SERVER HOSTNAME: %s"
,socket, host_name);
sockprintf(socket,"550 Access denied.");

rswindell
committed
mail_close_socket(socket);
thread_down();
return;
}
active_clients++, update_clients();
/* SPAM Filters (mail-abuse.org) */
dnsbl_result.s_addr = dns_blacklisted(socket,smtp.client_addr.sin_addr,host_name,dnsbl,dnsbl_ip);
if(dnsbl_result.s_addr) {
lprintf("%04d !SMTP BLACKLISTED SERVER on %s: %s [%s] = %s"
,socket, dnsbl, host_name, dnsbl_ip, inet_ntoa(dnsbl_result));
if(startup->options&MAIL_OPT_DNSBL_REFUSE) {
sprintf(str,"Listed on %s as %s", dnsbl, inet_ntoa(dnsbl_result));
spamlog(&scfg, "SMTP", "SESSION REFUSED", str, host_name, dnsbl_ip, NULL, NULL);
sockprintf(socket
,"550 Mail from %s refused due to listing at %s"
,dnsbl_ip, dnsbl);
mail_close_socket(socket);
lprintf("%04d !SMTP REFUSED SESSION from blacklisted server"
thread_down();
if(active_clients)
active_clients--, update_clients();
sprintf(smb.file,"%smail",scfg.data_dir);
if(smb_islocked(&smb)) {
lprintf("%04d !SMTP MAIL BASE LOCKED: %s"
,socket, smb.last_error);
sockprintf(socket,sys_unavail);
mail_close_socket(socket);
thread_down();
if(active_clients)
active_clients--, update_clients();
return;
}
srand(time(NULL)); /* seed random number generator */
rand(); /* throw-away first result */
sprintf(session_id,"%x%x%lx",socket,rand(),clock());
sprintf(rcptlst_fname,"%sSMTP.%s.lst", scfg.data_dir, session_id);
rcptlst=fopen(rcptlst_fname,"w+");
if(rcptlst==NULL) {

rswindell
committed
lprintf("%04d !SMTP ERROR %d creating recipient list: %s"
,socket, errno, rcptlst_fname);
sockprintf(socket,sys_error);

rswindell
committed
mail_close_socket(socket);
if(active_clients)
active_clients--, update_clients();
if(trashcan(&scfg,host_name,"smtpspy")
|| trashcan(&scfg,host_ip,"smtpspy")) {
sprintf(str,"%sSMTPSPY.TXT", scfg.data_dir);
spy=fopen(str,"a");
}
/* Initialize client display */
client.size=sizeof(client);
client.time=time(NULL);
SAFECOPY(client.addr,host_ip);
SAFECOPY(client.host,host_name);
client.port=ntohs(smtp.client_addr.sin_port);
client.protocol="SMTP";
client.user="<unknown>";
client_on(socket,&client,FALSE /* update */);
sprintf(str,"SMTP: %s",host_ip);
status(str);
sockprintf(socket,"220 %s Synchronet SMTP Server %s-%s Ready"
,startup->host_name,revision,PLATFORM_DESC);
while(1) {
rd = sockreadline(socket, buf, sizeof(buf));
if(rd<0)
truncsp(buf);
if(spy!=NULL)
fprintf(spy,"%s\n",buf);
if(state>=SMTP_STATE_DATA_HEADER) {
if(!strcmp(buf,".")) {

rswindell
committed
state=SMTP_STATE_HELO; /* RESET state machine here in case of error */

rswindell
committed
if(msgtxt==NULL) {
lprintf("%04d !SMTP NO MESSAGE TEXT FILE POINTER?", socket);
sockprintf(socket,"554 No message text");
continue;
}
if(ftell(msgtxt)<1) {
lprintf("%04d !SMTP INVALID MESSAGE LENGTH: %ld (%lu lines)"
, socket, ftell(msgtxt), lines);
sockprintf(socket,"554 No message text");
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
lprintf("%04d SMTP End of message (body: %lu lines, %lu bytes, header: %lu lines, %lu bytes)"
, socket, lines, ftell(msgtxt)-hdr_len, hdr_lines, hdr_len);
if(telegram==TRUE) { /* Telegram */
const char* head="\1n\1h\1cInstant Message\1n from \1h\1y";
const char* tail="\1n:\r\n\1h";
rewind(msgtxt);
length=filelength(fileno(msgtxt));
p=strchr(sender_addr,'@');
if(p==NULL || resolve_ip(p+1)!=smtp.client_addr.sin_addr.s_addr)
/* Append real IP and hostname if different */
sprintf(str,"%s%s\r\n\1w[\1n%s\1h] (\1n%s\1h)%s"
,head,sender_addr,host_ip,host_name,tail);
else
sprintf(str,"%s%s%s",head,sender_addr,tail);
if((telegram_buf=(char*)malloc(length+strlen(str)+1))==NULL) {
lprintf("%04d !SMTP ERROR allocating %lu bytes of memory for telegram from %s"
,socket,length+strlen(str)+1,sender_addr);
sockprintf(socket, "452 Insufficient system storage");
continue;
}
strcpy(telegram_buf,str); /* can't use SAFECOPY here */
if(fread(telegram_buf+strlen(str),1,length,msgtxt)!=length) {
lprintf("%04d !SMTP ERROR reading %lu bytes from telegram file"
,socket,length);
sockprintf(socket, "452 Insufficient system storage");
free(telegram_buf);
continue;
}
telegram_buf[length+strlen(str)]=0; /* Need ASCIIZ */
/* Send telegram to users */
rewind(rcptlst);
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
rcpt_count=0;
while(!feof(rcptlst) && rcpt_count<startup->max_recipients) {
if(fgets(str,sizeof(str),rcptlst)==NULL)
break;
usernum=atoi(str);
if(fgets(rcpt_name,sizeof(rcpt_name),rcptlst)==NULL)
break;
truncsp(rcpt_name);
if(fgets(rcpt_addr,sizeof(rcpt_addr),rcptlst)==NULL)
break;
truncsp(rcpt_addr);
putsmsg(&scfg,usernum,telegram_buf);
lprintf("%04d SMTP Created telegram (%ld/%u bytes) from %s to %s <%s>"
,socket, length, strlen(telegram_buf), sender_addr, rcpt_name, rcpt_addr);
rcpt_count++;
}
free(telegram_buf);
sockprintf(socket,ok_rsp);
telegram=FALSE;
continue;
}
fclose(msgtxt), msgtxt=NULL;
fclose(rcptlst), rcptlst=NULL;
/* External Mail Processing here */
if(startup->proc_cfg_file[0]
&& (proc_cfg=fopen(startup->proc_cfg_file,"r"))!=NULL) {
sprintf(proc_err_fname,"%sSMTP.%s.err", scfg.data_dir, session_id);
remove(proc_err_fname);
while(!feof(proc_cfg)) {
if(!fgets(tmp,sizeof(tmp),proc_cfg))
break;
truncsp(tmp);
p=tmp;
SKIP_WHITESPACE(p);
if(*p==';' || *p==0) /* comment or blank line */
continue;
lprintf("%04d SMTP executing external process: %s", socket, p);
system(mailcmdstr(p, msgtxt_fname, rcptlst_fname, proc_err_fname
,host_name, host_ip, relay_user.number, str));
if(flength(proc_err_fname)>0)
break;
if(!fexist(msgtxt_fname) || !fexist(rcptlst_fname))
break;
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
}
fclose(proc_cfg);
if(flength(proc_err_fname)>0
&& (proc_err=fopen(proc_err_fname,"r"))!=NULL) {
while(!feof(proc_err)) {
if(!fgets(str,sizeof(str),proc_err))
break;
truncsp(str);
lprintf("%04d !SMTP external process error: %s", socket, str);
i=atoi(str);
if(i>=100 && i<1000)
sockprintf(socket,"%s", str);
else
sockprintf(socket,"554%c%s"
,ftell(proc_err)<filelength(fileno(proc_err)) ? '-' : ' '
,str);
}
fclose(proc_err);
remove(proc_err_fname);
continue;
}
if(!fexist(msgtxt_fname) || !fexist(rcptlst_fname)) {
lprintf("%04d SMTP external process removed %s"
,socket, fexist(msgtxt_fname)==FALSE ? "message text" : "recipient list");
sockprintf(socket,ok_rsp);
continue;
}
}
/* Re-open files */
if((rcptlst=fopen(rcptlst_fname,"r"))==NULL) {
lprintf("%04d !SMTP ERROR %d re-opening recipient list: %s"
,socket, errno, rcptlst_fname);
sockprintf(socket,sys_error);
continue;
}
if((msgtxt=fopen(msgtxt_fname,"rb"))==NULL) {
lprintf("%04d !SMTP ERROR %d re-opening message file: %s"
,socket, errno, msgtxt_fname);
sockprintf(socket,sys_error);
continue;
}
/* Initialize message header */
smb_freemsgmem(&msg);
memset(&msg,0,sizeof(smbmsg_t));
/* Parse message header here */
hfield_type=UNKNOWN;
smb_error=0; /* no SMB error */
while(!feof(msgtxt)) {
if(!fgets(buf,sizeof(buf),msgtxt))
break;
truncsp(buf);
if(buf[0]==0) /* blank line marks end of header */
break;
if(!strnicmp(buf, "SUBJECT:",8)) {
p=buf+8;
SKIP_WHITESPACE(p);
if(relay_user.number==0 && dnsbl_result.s_addr && startup->dnsbl_tag[0]
&& !(startup->options&MAIL_OPT_DNSBL_IGNORE)) {
sprintf(str,"%.*s: %.*s"
,(int)sizeof(str)/2, startup->dnsbl_tag
,(int)sizeof(str)/2, p);
p=str;
lprintf("%04d !SMTP TAGGED MAIL SUBJECT from blacklisted server with: %s"
,socket, startup->dnsbl_tag);
}
smb_hfield_str(&msg, SUBJECT, p);
msg.idx.subj=subject_crc(p);
continue;
}
if(!strnicmp(buf, "FROM:", 5)
&& !chk_email_addr(socket,buf+5,host_name,host_ip,rcpt_addr,reverse_path))
break;
if((smb_error=parse_header_field(buf,&msg,&hfield_type))!=0) {
if(smb_error==SMB_ERR_HDR_LEN)
lprintf("%04d !SMTP MESSAGE HEADER EXCEEDS %u BYTES"
,socket, SMB_MAX_HDR_LEN);
else
lprintf("%04d !SMTP ERROR %d adding header field: %s"
,socket, smb_error, buf);
break;
}
}
if(smb_error!=0) { /* SMB Error */
sockprintf(socket, "452 Insufficient system storage");
continue;
}
if((p=smb_get_hfield(&msg, RFC822TO, NULL))!=NULL) {
if(*p=='<') p++;
SAFECOPY(rcpt_name,p);
truncstr(rcpt_name,">");
}
if((p=smb_get_hfield(&msg, RFC822FROM, NULL))!=NULL) {
/* Get the sender's address */
if((tp=strchr(p,'<'))!=NULL)
tp++;
else
tp=p;
SKIP_WHITESPACE(tp);
SAFECOPY(sender_addr,tp);
truncstr(sender_addr,">( ");
SAFECOPY(tmp,p);
p=tmp;
/* Get the sender's "name" (if possible) */
if((tp=strchr(p,'('))!=NULL) { /* name in parenthesis? */
p=tp+1;
tp=strchr(p,')');
} else if((tp=strchr(p,'"'))!=NULL) { /* name in quotes? */
p=tp+1;
tp=strchr(p,'"');
} else if(*p=='<') { /* address in brackets? */
p++;
tp=strchr(p,'>');
} else /* name, then address in brackets */
tp=strchr(p,'<');
if(tp) *tp=0;
SAFECOPY(sender,p);