Newer
Older
lprintf(LOG_CRIT,"%04d %s !ERROR %d (%d) getting address/port"
,socket, client.protocol, i, ERROR_VALUE);
sockprintf(socket,client.protocol,session,sys_error);
mail_close_socket(&socket, &session);
if((mailproc_to_match=malloc(sizeof(BOOL)*mailproc_count))==NULL) {
lprintf(LOG_CRIT,"%04d %s !ERROR allocating memory for mailproc_to_match", socket, client.protocol);
sockprintf(socket,client.protocol,session,sys_error);
mail_close_socket(&socket, &session);
thread_down();
return;
}
memset(mailproc_to_match,FALSE,sizeof(BOOL)*mailproc_count);
memset(&smb,0,sizeof(smb));

rswindell
committed
memset(&msg,0,sizeof(msg));

rswindell
committed
memset(&user,0,sizeof(user));
memset(&relay_user,0,sizeof(relay_user));
lprintf(LOG_INFO,"%04d %s Connection accepted on port %u from: %s port %u"
,socket, client.protocol, inet_addrport(&server_addr), host_ip, inet_addrport(&smtp.client_addr));
SAFECOPY(host_name, STR_NO_HOSTNAME);
if(!(startup->options&MAIL_OPT_NO_HOST_LOOKUP)) {
getnameinfo(&smtp.client_addr.addr, smtp.client_addr_len, host_name, sizeof(host_name), NULL, 0, NI_NAMEREQD);
lprintf(LOG_INFO,"%04d %s Hostname: %s [%s]", socket, client.protocol, host_name, host_ip);
protected_uint32_adjust(&active_clients, 1);
update_clients();
SAFECOPY(hello_name,host_name);
SAFEPRINTF(spam_bait,"%sspambait.cfg",scfg.ctrl_dir);
SAFEPRINTF(spam_block,"%sspamblock.cfg",scfg.ctrl_dir);
SAFEPRINTF(spam_block_exemptions,"%sspamblock_exempt.cfg",scfg.ctrl_dir);
inet_addrtop(&server_addr,server_ip,sizeof(server_ip));
if(strcmp(server_ip, host_ip)==0) {
/* local connection */
dnsbl_result.s_addr=0;
} else {
ulong banned = loginBanned(&scfg, startup->login_attempt_list, socket, host_name, startup->login_attempt, &attempted);
lprintf(LOG_NOTICE, "%04d !TEMPORARY BAN of %s (%lu login attempts, last: %s) - remaining: %s"
,socket, host_ip, attempted.count-attempted.dupes, attempted.user, seconds_to_str(banned, ban_duration));
mail_close_socket(&socket, &session);
thread_down();
protected_uint32_adjust(&active_clients, -1);
update_clients();
free(mailproc_to_match);
return;
}
spam_block_exempt = findstr(host_ip,spam_block_exemptions) || findstr(host_name,spam_block_exemptions);
if(trashcan(&scfg,host_ip,"ip")
|| ((!spam_block_exempt) && findstr(host_ip,spam_block))) {
lprintf(LOG_NOTICE,"%04d %s !CLIENT IP ADDRESS BLOCKED: %s (%lu total)"
,socket, client.protocol, host_ip, ++stats.sessions_refused);
sockprintf(socket,client.protocol,session,"550 CLIENT IP ADDRESS BLOCKED: %s", host_ip);
mail_close_socket(&socket, &session);
thread_down();
protected_uint32_adjust(&active_clients, -1);
update_clients();
return;
}
if(trashcan(&scfg,host_name,"host")) {
lprintf(LOG_NOTICE,"%04d %s !CLIENT HOSTNAME BLOCKED: %s (%lu total)"
,socket, client.protocol, host_name, ++stats.sessions_refused);
sockprintf(socket,client.protocol,session,"550 CLIENT HOSTNAME BLOCKED: %s", host_name);
mail_close_socket(&socket, &session);
thread_down();
protected_uint32_adjust(&active_clients, -1);
update_clients();
/* SPAM Filters (mail-abuse.org) */
dnsbl_result.s_addr = dns_blacklisted(socket,client.protocol,&smtp.client_addr,host_name,dnsbl,dnsbl_ip);
if(dnsbl_result.s_addr) {
lprintf(LOG_NOTICE,"%04d %s BLACKLISTED SERVER on %s: %s [%s] = %s"
,socket, client.protocol, dnsbl, host_name, dnsbl_ip, inet_ntoa(dnsbl_result));
if(startup->options&MAIL_OPT_DNSBL_REFUSE) {
SAFEPRINTF2(str,"Listed on %s as %s", dnsbl, inet_ntoa(dnsbl_result));
spamlog(&scfg, (char*)client.protocol, "SESSION REFUSED", str, host_name, dnsbl_ip, NULL, NULL);
sockprintf(socket,client.protocol,session
,"550 Mail from %s refused due to listing at %s"
,dnsbl_ip, dnsbl);
mail_close_socket(&socket, &session);
lprintf(LOG_NOTICE,"%04d %s !REFUSED SESSION from blacklisted server (%lu total)"
,socket, client.protocol, ++stats.sessions_refused);
thread_down();
protected_uint32_adjust(&active_clients, -1);
update_clients();
return;
}
}
SAFEPRINTF(smb.file,"%smail",scfg.data_dir);
if(smb_islocked(&smb)) {
lprintf(LOG_WARNING,"%04d %s !MAIL BASE LOCKED: %s"
,socket, client.protocol, smb.last_error);
sockprintf(socket,client.protocol,session,sys_unavail);
mail_close_socket(&socket, &session);
thread_down();
protected_uint32_adjust(&active_clients, -1);
update_clients();
return;
}
SAFEPRINTF(spam.file,"%sspam",scfg.data_dir);
spam.retry_time=scfg.smb_retry_time;
spam.subnum=INVALID_SUB;
srand((unsigned int)(time(NULL) ^ (time_t)GetCurrentThreadId())); /* seed random number generator */
rand(); /* throw-away first result */
SAFEPRINTF4(session_id,"%x%x%x%lx",getpid(),socket,rand(),(long)clock());
lprintf(LOG_DEBUG,"%04d %s Session ID=%s", socket, client.protocol, session_id);
SAFEPRINTF3(msgtxt_fname,"%sSBBS_%s.%s.msg", scfg.temp_dir, client.protocol, session_id);
SAFEPRINTF3(newtxt_fname,"%sSBBS_%s.%s.new", scfg.temp_dir, client.protocol, session_id);
SAFEPRINTF3(logtxt_fname,"%sSBBS_%s.%s.log", scfg.temp_dir, client.protocol, session_id);
SAFEPRINTF3(rcptlst_fname,"%sSBBS_%s.%s.lst", scfg.temp_dir, client.protocol, session_id);
rcptlst=fopen(rcptlst_fname,"w+");
if(rcptlst==NULL) {
lprintf(LOG_CRIT,"%04d %s !ERROR %d creating recipient list: %s"
,socket, client.protocol, errno, rcptlst_fname);
sockprintf(socket,client.protocol,session,sys_error);
mail_close_socket(&socket, &session);
protected_uint32_adjust(&active_clients, -1);
update_clients();
if(trashcan(&scfg,host_name,"smtpspy")
|| trashcan(&scfg,host_ip,"smtpspy")) {
SAFEPRINTF(str,"%ssmtpspy.txt", scfg.logs_dir);
spy=fopen(str,"a");
}
/* Initialize client display */
client.size=sizeof(client);
client.time=time32(NULL);
SAFECOPY(client.addr,host_ip);
SAFECOPY(client.host,host_name);
client.user=STR_UNKNOWN_USER;
client_on(socket,&client,FALSE /* update */);
SAFEPRINTF(str,"SMTP: %s",host_ip);
&& (login_attempts=loginAttempts(startup->login_attempt_list, &smtp.client_addr)) > 1) {
lprintf(LOG_DEBUG,"%04d %s Throttling suspicious connection from: %s (%lu login attempts)"
,socket, client.protocol, host_ip, login_attempts);
mswait(login_attempts*startup->login_attempt.throttle);
}
/* SMTP session active: */
sockprintf(socket,client.protocol,session,"220 %s Synchronet %s Server %s-%s Ready"
,startup->host_name, client.protocol, revision, PLATFORM_DESC);
rd = sockreadline(socket, client.protocol, session, buf, sizeof(buf));
if(rd<0)
truncsp(buf);
if(spy!=NULL)
fprintf(spy,"%s\n",buf);
if(relay_user.number==0 && dnsbl_result.s_addr && startup->options&MAIL_OPT_DNSBL_THROTTLE)
mswait(DNSBL_THROTTLE_VALUE);
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(LOG_ERR,"%04d %s !NO MESSAGE TEXT FILE POINTER?", socket, client.protocol);
sockprintf(socket,client.protocol,session,"554 No message text");
continue;
}
if(ftell(msgtxt)<1) {
lprintf(LOG_ERR,"%04d %s !INVALID MESSAGE LENGTH: %ld (%lu lines)"
, socket, client.protocol, ftell(msgtxt), lines);
sockprintf(socket,client.protocol,session,"554 No message text");
lprintf(LOG_INFO,"%04d %s End of message (body: %lu lines, %lu bytes, header: %lu lines, %lu bytes)"
, socket, client.protocol, lines, ftell(msgtxt)-hdr_len, hdr_lines, hdr_len);
if(!socket_check(socket, NULL, NULL, 0)) {
lprintf(LOG_WARNING,"%04d %s !sender disconnected (premature evacuation)", socket, client.protocol);
continue;
}
stats.msgs_received++;
/* Twit-listing (sender's name and e-mail addresses) here */
SAFEPRINTF(path,"%stwitlist.cfg",scfg.ctrl_dir);
if(fexist(path) && (findstr(sender,path) || findstr(sender_addr,path))) {
lprintf(LOG_NOTICE,"%04d %s !FILTERING TWIT-LISTED SENDER: %s <%s> (%lu total)"
,socket, client.protocol, sender, sender_addr, ++stats.msgs_refused);
SAFEPRINTF2(tmp,"Twit-listed sender: %s <%s>", sender, sender_addr);
spamlog(&scfg, (char*)client.protocol, "REFUSED", tmp, host_name, host_ip, rcpt_addr, reverse_path);
sockprintf(socket,client.protocol,session, "554 Sender not allowed.");
continue;
}
if(telegram==TRUE) { /* Telegram */
const char* head="\1n\1h\1cInstant Message\1n from \1h\1y";
const char* tail="\1n:\r\n\1h";
struct addrinfo ai;
struct addrinfo *res,*cur;
BOOL matched=FALSE;
rewind(msgtxt);
length=filelength(fileno(msgtxt));
p=strchr(sender_addr,'@');
memset(&ai, 0, sizeof(ai));
ai.ai_flags = AI_PASSIVE;
ai.ai_family = smtp.client_addr.addr.sa_family;
if(getaddrinfo(p+1, NULL, &ai, &res) != 0)
p=NULL;
else {
for(cur=res; cur; cur=cur->ai_next) {
char cur_ip[INET6_ADDRSTRLEN];
if(inet_addrtop((void *)cur->ai_addr, cur_ip, sizeof(cur_ip))) {
if(strcmp(host_ip, cur_ip)==0)
matched=TRUE;
}
}
freeaddrinfo(res);
if(!matched)
p=NULL;
}
if(p==NULL)
/* Append real IP and hostname if different */
safe_snprintf(str,sizeof(str),"%s%s\r\n\1w[\1n%s\1h] (\1n%s\1h)%s"
,head,sender_addr,host_ip,host_name,tail);
else
safe_snprintf(str,sizeof(str),"%s%s%s",head,sender_addr,tail);
if((telegram_buf=(char*)malloc(length+strlen(str)+1))==NULL) {
lprintf(LOG_CRIT,"%04d %s !ERROR allocating %lu bytes of memory for telegram from %s"
,socket, client.protocol,length+strlen(str)+1,sender_addr);
sockprintf(socket,client.protocol,session, insuf_stor);
continue;
}
strcpy(telegram_buf,str); /* can't use SAFECOPY here */
if(fread(telegram_buf+strlen(str),1,length,msgtxt)!=length) {
lprintf(LOG_ERR,"%04d %s !ERROR reading %lu bytes from telegram file"
,socket, client.protocol,length);
sockprintf(socket,client.protocol,session, insuf_stor);
free(telegram_buf);
continue;
}
telegram_buf[length+strlen(str)]=0; /* Need ASCIIZ */
/* Send telegram to users */
sec_list=iniReadSectionList(rcptlst,NULL); /* Each section is a recipient */
for(rcpt_count=0; sec_list!=NULL
&& sec_list[rcpt_count]!=NULL
&& (startup->max_recipients==0 || rcpt_count<startup->max_recipients); rcpt_count++) {
section=sec_list[rcpt_count];
SAFECOPY(rcpt_to,iniReadString(rcptlst,section ,smb_hfieldtype(RECIPIENT),"unknown",value));
usernum=iniReadInteger(rcptlst,section ,smb_hfieldtype(RECIPIENTEXT),0);
SAFECOPY(rcpt_addr,iniReadString(rcptlst,section ,smb_hfieldtype(RECIPIENTNETADDR),rcpt_to,value));
if((i=putsmsg(&scfg,usernum,telegram_buf))==0)
lprintf(LOG_INFO,"%04d %s Created telegram (%ld/%lu bytes) from %s to %s <%s>"
,socket, client.protocol, length, (ulong)strlen(telegram_buf), sender_addr, rcpt_to, rcpt_addr);
else
lprintf(LOG_ERR,"%04d %s !ERROR %d creating telegram from %s to %s <%s>"
,socket, client.protocol, i, sender_addr, rcpt_to, rcpt_addr);
}
iniFreeStringList(sec_list);
free(telegram_buf);
sockprintf(socket,client.protocol,session,ok_rsp);
telegram=FALSE;
continue;
}
fclose(msgtxt), msgtxt=NULL;
fclose(rcptlst), rcptlst=NULL;
/* External Mail Processing here */
mailproc=NULL;
msg_handled=FALSE;
if(mailproc_count) {
SAFEPRINTF3(proc_err_fname,"%sSBBS_%s.%s.err", scfg.temp_dir, client.protocol, session_id);
remove(proc_err_fname);
for(i=0;i<mailproc_count && !msg_handled;i++) {
struct mailproc* mp=&mailproc_list[i];
if(mp->disabled)
if(!mp->process_dnsbl && dnsbl_result.s_addr)
continue;
if(!mp->process_spam && spam_bait_result)
continue;
if(!chk_ar(&scfg,mp->ar,&relay_user,&client))
if(mp->to!=NULL && !mailproc_to_match[i])
continue;
if(mp->from!=NULL
&& !findstr_in_list(sender_addr, mp->from))
mailcmdstr(mp->cmdline
,msgtxt_fname, newtxt_fname, logtxt_fname
,rcptlst_fname, proc_err_fname
,host_name, host_ip, relay_user.number
,sender, sender_addr, reverse_path, str);
lprintf(LOG_INFO,"%04d %s Executing external mail processor: %s"
,socket, client.protocol, mp->name);
lprintf(LOG_DEBUG,"%04d %s Executing external command: %s"
,socket, client.protocol, str);
if((j=system(str))!=0) {
lprintf(LOG_NOTICE,"%04d %s system(%s) returned %d (errno: %d)"
,socket, client.protocol, str, j, errno);
if(mp->ignore_on_error) {
lprintf(LOG_WARNING,"%04d %s !IGNORED MAIL due to mail processor (%s) error: %d"
,socket, client.protocol, mp->name, j);
msg_handled=TRUE;
}
}
} else { /* JavaScript */
,msgtxt_fname, newtxt_fname, logtxt_fname
,rcpt_addr
,rcptlst_fname, proc_err_fname
,sender, sender_addr, reverse_path, hello_name, &js_result
,client.protocol) || js_result!=0) {
#if 0 /* calling exit() in a script causes js_mailproc to return FALSE */
lprintf(LOG_NOTICE,"%04d !SMTP JavaScript mailproc command (%s) failed (returned: %d)"
if(mailproc->ignore_on_error) {
lprintf(LOG_WARNING,"%04d !SMTP IGNORED MAIL due to mail processor (%s) failure"
,socket, mailproc->name);
msg_handled=TRUE;
}
#endif
}
}
/* Log debug output (file) from mailproc: */
if(flength(logtxt_fname) > 0 && (proc_out=fopen(logtxt_fname,"r"))!=NULL) {
while(!feof(proc_out)) {
if(!fgets(str,sizeof(str),proc_out))
break;
truncsp(str);
lprintf(LOG_DEBUG,"%04d %s External mail processor (%s) debug: %s"
,socket, client.protocol, mp->name, str);
}
fclose(proc_out);
}
remove(logtxt_fname);
if(!mp->passthru || flength(proc_err_fname)>0 || !fexist(msgtxt_fname) || !fexist(rcptlst_fname)) {
mailproc=mp;
msg_handled=TRUE;
break;
}
if(flength(proc_err_fname)>0
&& (proc_out=fopen(proc_err_fname,"r"))!=NULL) {
lprintf(LOG_WARNING,"%04d %s !External mail processor (%s) created: %s"
,socket, client.protocol, mailproc->name, proc_err_fname);
while(!feof(proc_out)) {
int n;
if(!fgets(str,sizeof(str),proc_out))
break;
truncsp(str);
lprintf(LOG_WARNING,"%04d %s !External mail processor (%s) error: %s"
,socket, client.protocol, mailproc->name, str);
n=atoi(str);
if(n>=100 && n<1000)
sockprintf(socket,client.protocol,session,"%s", str);
else
sockprintf(socket,client.protocol,session,"554%c%s"
,ftell(proc_out)<filelength(fileno(proc_out)) ? '-' : ' '
,str);
}
fclose(proc_out);
msg_handled=TRUE;
}
else if(!fexist(msgtxt_fname) || !fexist(rcptlst_fname)) {
lprintf(LOG_NOTICE,"%04d %s External mail processor (%s) removed %s file"
,socket, client.protocol
,mailproc->name
,fexist(msgtxt_fname)==FALSE ? "message text" : "recipient list");
sockprintf(socket,client.protocol,session,ok_rsp);
msg_handled=TRUE;
}
else if(msg_handled)
sockprintf(socket,client.protocol,session,ok_rsp);
remove(proc_err_fname); /* Remove error file here */
}
/* Re-open files */
/* We must do this before continuing for handled msgs */
/* to prevent freopen(NULL) and orphaned temp files */
if((rcptlst=fopen(rcptlst_fname,fexist(rcptlst_fname) ? "r":"w+"))==NULL) {
lprintf(LOG_ERR,"%04d %s !ERROR %d re-opening recipient list: %s"
,socket, client.protocol, errno, rcptlst_fname);
if(!msg_handled)
sockprintf(socket,client.protocol,session,sys_error);
continue;
}
if(!msg_handled && subnum==INVALID_SUB && iniReadSectionCount(rcptlst,NULL) < 1) {
lprintf(LOG_DEBUG,"%04d %s No recipients in recipient list file (message handled by external mail processor?)"
,socket, client.protocol);
sockprintf(socket,client.protocol,session,ok_rsp);
msg_handled=TRUE;
}
if(msg_handled) {
if(mailproc!=NULL)
lprintf(LOG_NOTICE,"%04d %s Message handled by external mail processor (%s, %lu total)"
,socket, client.protocol, mailproc->name, ++mailproc->handled);
continue;
}
/* If mailproc has written new message text to .new file, use that instead of .msg */
if(flength(newtxt_fname) > 0) {
remove(msgtxt_fname);
SAFECOPY(msgtxt_fname, newtxt_fname);
} else
remove(newtxt_fname);
if((msgtxt=fopen(msgtxt_fname,"rb"))==NULL) {
lprintf(LOG_ERR,"%04d %s !ERROR %d re-opening message file: %s"
,socket, client.protocol, errno, msgtxt_fname);
sockprintf(socket,client.protocol,session,sys_error);
continue;
}
/* Initialize message header */
smb_freemsgmem(&msg);
memset(&msg,0,sizeof(smbmsg_t));
/* Parse message header here */
hfield_type=UNKNOWN;
smb_error=SMB_SUCCESS; /* no SMB error */
errmsg=insuf_stor;
while(!feof(msgtxt)) {
char field[32];
if(!fgets(buf,sizeof(buf),msgtxt))
break;
truncsp(buf);
if(buf[0]==0) /* blank line marks end of header */
break;
if((p=get_header_field(buf, field, sizeof(field)))!=NULL) {
//normalize_hfield_value(p);
if(stricmp(field, "SUBJECT")==0) {
/* SPAM Filtering/Logging */
if(relay_user.number==0) {
if(trashcan(&scfg,p,"subject")) {
lprintf(LOG_NOTICE,"%04d %s !BLOCKED SUBJECT (%s) from: %s (%lu total)"
,socket, client.protocol, p, reverse_path, ++stats.msgs_refused);
SAFEPRINTF2(tmp,"Blocked subject (%s) from: %s"
,p, reverse_path);
spamlog(&scfg, (char*)client.protocol, "REFUSED"
,tmp, host_name, host_ip, rcpt_addr, reverse_path);
errmsg="554 Subject not allowed.";
smb_error=SMB_FAILURE;
break;
}
if(dnsbl_result.s_addr && startup->dnsbl_tag[0] && !(startup->options&MAIL_OPT_DNSBL_IGNORE)) {
safe_snprintf(str,sizeof(str),"%.*s: %.*s"
,(int)sizeof(str)/2, startup->dnsbl_tag
,(int)sizeof(str)/2, p);
p=str;
lprintf(LOG_NOTICE,"%04d %s TAGGED MAIL SUBJECT from blacklisted server with: %s"
,socket, client.protocol, startup->dnsbl_tag);
msg.hdr.attr |= MSG_SPAM;
}
}
smb_hfield_str(&msg, hfield_type=RFC822SUBJECT, p);
continue;
}
if(relay_user.number==0 && stricmp(field, "FROM")==0
&& !chk_email_addr(socket, client.protocol,p,host_name,host_ip,rcpt_addr,reverse_path,"FROM")) {
errmsg="554 Sender not allowed.";
smb_error=SMB_FAILURE;
break;
}
if(relay_user.number==0 && stricmp(field, "TO")==0 && !spam_bait_result
&& !chk_email_addr(socket, client.protocol,p,host_name,host_ip,rcpt_addr,reverse_path,"TO")) {
errmsg="550 Unknown user.";
smb_error=SMB_FAILURE;
break;
}
if(stricmp(field, "X-Spam-Flag") == 0 && stricmp(p, "Yes") == 0)
msg.hdr.attr |= MSG_SPAM; /* e.g. flagged by SpamAssasin */
}
if((smb_error=parse_header_field((char*)buf, &msg, &hfield_type))!=SMB_SUCCESS) {
if(smb_error==SMB_ERR_HDR_LEN)
lprintf(LOG_WARNING,"%04d %s !MESSAGE HEADER EXCEEDS %u BYTES"
,socket, client.protocol, SMB_MAX_HDR_LEN);
lprintf(LOG_ERR,"%04d %s !ERROR %d adding header field: %s"
,socket, client.protocol, smb_error, buf);
break;
}
}
if(smb_error!=SMB_SUCCESS) { /* SMB Error */
sockprintf(socket,client.protocol,session, "%s", errmsg);
stats.msgs_refused++;
}
hfield_t* hfield;
if((p=smb_get_hfield(&msg, RFC822TO, &hfield))!=NULL) {
char* np = strdup(p);
if(np != NULL) {
if(mimehdr_value_decode(np, &msg))
smb_hfield_str(&msg, RECIPIENTLIST, np);
else
hfield->type = RECIPIENTLIST;
parse_mail_address(np
,rcpt_name ,sizeof(rcpt_name)-1
,rcpt_addr ,sizeof(rcpt_addr)-1);
free(np);
}
}
if((p=smb_get_hfield(&msg, RFC822FROM, NULL))!=NULL) {
char* np = strdup(p);
if(np != NULL) {
mimehdr_value_decode(np, &msg);
parse_mail_address(p
,sender ,sizeof(sender)-1
,sender_addr,sizeof(sender_addr)-1);
free(np);
}
}
dnsbl_recvhdr=FALSE;
if(startup->options&MAIL_OPT_DNSBL_CHKRECVHDRS) {
for(i=0;!dnsbl_result.s_addr && i<msg.total_hfields;i++) {
if(msg.hfield[i].type == SMTPRECEIVED) {
if(chk_received_hdr(socket, client.protocol,msg.hfield_dat[i],&dnsbl_result,dnsbl,dnsbl_ip)) {
dnsbl_recvhdr=TRUE;
break;
}
}
}
if(relay_user.number==0 && dnsbl_result.s_addr && !(startup->options&MAIL_OPT_DNSBL_IGNORE)) {
msg.hdr.attr |= MSG_SPAM;
/* tag message as spam */
if(startup->dnsbl_hdr[0]) {
safe_snprintf(str,sizeof(str),"%s: %s is listed on %s as %s"
,startup->dnsbl_hdr, dnsbl_ip
,dnsbl, inet_ntoa(dnsbl_result));
smb_hfield_str(&msg, RFC822HEADER, str);
lprintf(LOG_NOTICE,"%04d %s TAGGED MAIL HEADER from blacklisted server with: %s"
,socket, client.protocol, startup->dnsbl_hdr);
if(startup->dnsbl_hdr[0] || startup->dnsbl_tag[0]) {
SAFEPRINTF2(str,"Listed on %s as %s", dnsbl, inet_ntoa(dnsbl_result));
spamlog(&scfg, (char*)client.protocol, "TAGGED", str, host_name, dnsbl_ip, rcpt_addr, reverse_path);
if(dnsbl_recvhdr) /* DNSBL-listed IP found in Received header? */
dnsbl_result.s_addr=0; /* Reset DNSBL look-up result between messages */
if((scfg.sys_misc&SM_DELREADM)
|| ((startup->options&MAIL_OPT_KILL_READ_SPAM) && (msg.hdr.attr&MSG_SPAM)))
msg.hdr.attr |= MSG_KILLREAD;

rswindell
committed
if(sender[0]==0) {
lprintf(LOG_WARNING,"%04d %s !MISSING mail header 'FROM' field (%lu total)"
,socket, client.protocol, ++stats.msgs_refused);
sockprintf(socket,client.protocol,session, "554 Mail header missing 'FROM' field");
subnum=INVALID_SUB;

rswindell
committed
continue;
}
if(relay_user.number) {
SAFEPRINTF(str,"%u",relay_user.number);
smb_hfield_str(&msg, SENDEREXT, str);
}
if(relay_user.number && subnum!=INVALID_SUB) {
nettype=NET_NONE;
smb_hfield_str(&msg, SENDER, relay_user.alias);
} else {
nettype=NET_INTERNET;
smb_hfield_str(&msg, SENDER, sender);
smb_hfield(&msg, SENDERNETTYPE, sizeof(nettype), &nettype);
smb_hfield_str(&msg, SENDERNETADDR, sender_addr);
}
smb_hfield_str(&msg, SMTPREVERSEPATH, reverse_path);
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
if((p = smb_get_hfield(&msg, RFC822ORG, &hfield)) != NULL) {
char* np = strdup(p);
if(np != NULL) {
if(mimehdr_value_decode(np, &msg))
smb_hfield_str(&msg, SENDERORG, np);
else
hfield->type = SENDERORG;
free(np);
}
}
if((p = smb_get_hfield(&msg, RFC822CC, &hfield)) != NULL) {
char* np = strdup(p);
if(np != NULL) {
if(mimehdr_value_decode(np, &msg))
smb_hfield_str(&msg, SMB_CARBONCOPY, np);
else
hfield->type = SMB_CARBONCOPY;
free(np);
}
}
if((p = smb_get_hfield(&msg, RFC822SUBJECT, &hfield)) != NULL) {
char* np = strdup(p);
if(np != NULL) {
if(mimehdr_value_decode(np, &msg))
smb_hfield_str(&msg, SUBJECT, np);
else
hfield->type = SUBJECT;
free(np);
}
}
else
smb_hfield(&msg, SUBJECT, 0, NULL);

rswindell
committed
length=filelength(fileno(msgtxt))-ftell(msgtxt);
if(startup->max_msg_size && length>startup->max_msg_size) {
lprintf(LOG_WARNING,"%04d %s !Message size (%lu) exceeds maximum: %u bytes"
,socket, client.protocol,length,startup->max_msg_size);
sockprintf(socket,client.protocol,session, "552 Message size (%lu) exceeds maximum: %u bytes"
,length,startup->max_msg_size);
subnum=INVALID_SUB;
stats.msgs_refused++;
if((msgbuf=(char*)malloc(length+1))==NULL) {
lprintf(LOG_CRIT,"%04d %s !ERROR allocating %lu bytes of memory"
,socket, client.protocol,length+1);
sockprintf(socket,client.protocol,session, insuf_stor);
subnum=INVALID_SUB;
continue;
}
fread(msgbuf,length,1,msgtxt);
msgbuf[length]=0; /* ASCIIZ */
/* Do external JavaScript processing here? */
if(subnum!=INVALID_SUB) { /* Message Base */
uint reason;
if(relay_user.number==0)
memset(&relay_user,0,sizeof(relay_user));
if(!can_user_post(&scfg,subnum,&relay_user,&client,&reason)) {
lprintf(LOG_WARNING,"%04d %s !%s (user #%u) cannot post on %s (reason: %u)"
,socket, client.protocol, sender_addr, relay_user.number
,scfg.sub[subnum]->sname, reason + 1);
sockprintf(socket,client.protocol,session,"550 Insufficient access");
subnum=INVALID_SUB;
stats.msgs_refused++;
continue;
}
if(rcpt_name[0]==0)
strcpy(rcpt_name,"All");
smb_hfield_str(&msg, RECIPIENT, rcpt_name);
smb.subnum=subnum;
if((i=savemsg(&scfg, &smb, &msg, &client, startup->host_name, msgbuf, /* remsg: */NULL))!=SMB_SUCCESS) {
lprintf(LOG_WARNING,"%04d %s !ERROR %d (%s) posting message to %s (%s)"
,socket, client.protocol, i, smb.last_error, scfg.sub[subnum]->sname, smb.file);
sockprintf(socket,client.protocol,session, "452 ERROR %d (%s) posting message"
,i,smb.last_error);
} else {
lprintf(LOG_INFO,"%04d %s %s posted a message on %s (%s)"
,socket, client.protocol, sender_addr, scfg.sub[subnum]->sname, smb.file);
sockprintf(socket,client.protocol,session,ok_rsp);
if(relay_user.number != 0)
user_posted_msg(&scfg, &relay_user, 1);
signal_smtp_sem();
}
free(msgbuf);
smb_close(&smb);
subnum=INVALID_SUB;
continue;
}
/* Create/check hashes of known SPAM */
{
hash_t** hashes;
BOOL is_spam=spam_bait_result;
long sources=SMB_HASH_SOURCE_SPAM;
if((dnsbl_recvhdr || dnsbl_result.s_addr) && startup->options&MAIL_OPT_DNSBL_SPAMHASH)
is_spam=TRUE;
lprintf(LOG_DEBUG,"%04d %s Calculating message hashes (sources=%lx, msglen=%lu)"
,socket, client.protocol, sources, (ulong)strlen(msgbuf));
if((hashes=smb_msghashes(&msg, (uchar*)msgbuf, sources)) != NULL) {
for(i=0;hashes[i];i++)
lprintf(LOG_DEBUG,"%04d %s Message %s crc32=%x flags=%x length=%u"
,socket, client.protocol, smb_hashsourcetype(hashes[i]->source)
,hashes[i]->crc32, hashes[i]->flags, hashes[i]->length);
lprintf(LOG_DEBUG, "%04d %s Searching SPAM database for a match", socket, client.protocol);
if((i=smb_findhash(&spam, hashes, &found, sources, /* Mark: */TRUE))==SMB_SUCCESS) {
SAFEPRINTF3(str,"%s (%s) found in SPAM database (added on %s)"
,smb_hashsourcetype(found.source)
,smb_hashsource(&msg,found.source)
,timestr(&scfg,found.time,tmp)
lprintf(LOG_NOTICE,"%04d %s Message %s", socket, client.protocol, str);
if(!is_spam) {
spamlog(&scfg, (char*)client.protocol, "IGNORED"
,str, host_name, host_ip, rcpt_addr, reverse_path);
is_spam=TRUE;
}
} else {
lprintf(LOG_DEBUG, "%04d %s Done searching SPAM database", socket, client.protocol);
if(i!=SMB_ERR_NOT_FOUND)
lprintf(LOG_ERR,"%04d %s !ERROR %d (%s) opening SPAM database"
,socket, client.protocol, i, spam.last_error);
if(is_spam) {
size_t n,total=0;
for(n=0;hashes[n]!=NULL;n++)
if(!(hashes[n]->flags&SMB_HASH_MARKED)) {
lprintf(LOG_INFO,"%04d %s Adding message %s (%s) to SPAM database"
,socket, client.protocol
,smb_hashsourcetype(hashes[n]->source)
,smb_hashsource(&msg,hashes[n]->source)
);
}
lprintf(LOG_DEBUG,"%04d %s Adding %lu message hashes to SPAM database", socket, client.protocol, (ulong)total);
smb_addhashes(&spam, hashes, /* skip_marked: */TRUE);
}
if(i!=SMB_SUCCESS && !spam_bait_result && (dnsbl_recvhdr || dnsbl_result.s_addr))
is_spam=FALSE;
}
smb_close_hash(&spam);
smb_freehashes(hashes);
} else
lprintf(LOG_ERR,"%04d %s smb_msghashes returned NULL", socket, client.protocol);
if(is_spam || ((startup->options&MAIL_OPT_DNSBL_IGNORE) && (dnsbl_recvhdr || dnsbl_result.s_addr))) {
lprintf(LOG_NOTICE,"%04d %s !IGNORED SPAM MESSAGE (%lu total)"
,socket, client.protocol, ++stats.msgs_ignored);
SAFEPRINTF2(str,"Listed on %s as %s", dnsbl, inet_ntoa(dnsbl_result));
lprintf(LOG_NOTICE,"%04d %s !IGNORED MAIL from server: %s (%lu total)"
,socket, client.protocol, str, ++stats.msgs_ignored);
spamlog(&scfg, (char*)client.protocol, "IGNORED"
,str, host_name, dnsbl_ip, rcpt_addr, reverse_path);
sockprintf(socket,client.protocol,session,ok_rsp);
subnum=INVALID_SUB;
continue;
}
}
lprintf(LOG_DEBUG,"%04d %s Saving message to: '%s'", socket, client.protocol, rcpt_name);
/* E-mail */
smb.subnum=INVALID_SUB;
/* creates message data, but no header or index records (since msg.to==NULL) */
i=savemsg(&scfg, &smb, &msg, &client, startup->host_name, msgbuf, /* remsg: */NULL);
if(smb_countattachments(&smb, &msg, msgbuf) > 0)
msg.hdr.auxattr |= MSG_MIMEATTACH;
free(msgbuf);
if(i!=SMB_SUCCESS) {
smb_close(&smb);
lprintf(LOG_CRIT,"%04d %s !ERROR %d (%s) saving message"
,socket, client.protocol,i,smb.last_error);
sockprintf(socket,client.protocol,session, "452 ERROR %d (%s) saving message"
,i,smb.last_error);
continue;
}
lprintf(LOG_DEBUG,"%04d %s Saved message data to: '%s'", socket, client.protocol, rcpt_name);
sec_list=iniReadSectionList(rcptlst,NULL); /* Each section is a recipient */
for(rcpt_count=0; sec_list!=NULL
&& sec_list[rcpt_count]!=NULL
&& (startup->max_recipients==0 || rcpt_count<startup->max_recipients); rcpt_count++) {
section=sec_list[rcpt_count];
SAFECOPY(rcpt_to,iniReadString(rcptlst,section ,smb_hfieldtype(RECIPIENT),"unknown",value));
usernum=iniReadInteger(rcptlst,section ,smb_hfieldtype(RECIPIENTEXT),0);
agent=iniReadShortInt(rcptlst,section ,smb_hfieldtype(RECIPIENTAGENT),AGENT_PERSON);
nettype=iniReadShortInt(rcptlst,section ,smb_hfieldtype(RECIPIENTNETTYPE),NET_NONE);
SAFECOPY(rcpt_addr,iniReadString(rcptlst,section ,smb_hfieldtype(RECIPIENTNETADDR),str,value));
SAFECOPY(forward_path, iniReadString(rcptlst, section, smb_hfieldtype(SMTPFORWARDPATH), "", value));

rswindell
committed
if(nettype==NET_NONE /* Local destination */ && usernum==0) {
lprintf(LOG_ERR,"%04d %s !can't deliver mail to user #0"
,socket, client.protocol);
break;
}
if((i=smb_copymsgmem(&smb,&newmsg,&msg))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d %s !ERROR %d (%s) copying message"
,socket, client.protocol, i, smb.last_error);
break;
}
with_val = 0;
if (esmtp)
with_val |= WITH_ESMTP;
if (auth_login)
with_val |= WITH_AUTH;
if (session != -1)
with_val |= WITH_TLS;

rswindell
committed
snprintf(hdrfield,sizeof(hdrfield),
"from %s (%s [%s%s])\r\n"
" by %s [%s%s] (%s %s-%s) with %s\r\n"
" for %s; %s\r\n"
" (envelope-from %s)"
,host_name,hello_name
,smtp.client_addr.addr.sa_family==AF_INET6?"IPv6: ":""
,host_ip
,startup->host_name
,server_addr.addr.sa_family==AF_INET6?"IPv6: ":""
,server_ip
,server_name
,revision,PLATFORM_DESC
,with_clauses[with_val]
,rcpt_to,msgdate(msg.hdr.when_imported,date)
,reverse_path);
smb_hfield_add_str(&newmsg, SMTPRECEIVED, hdrfield, /* insert: */TRUE);

rswindell
committed
if(nettype == NET_FIDO) {
char* tp = strchr(rcpt_name, '@');
if(tp != NULL)
*tp = 0;
// Remove "(ftn_addr)" portion of to name
SAFEPRINTF(str,"(%s)", rcpt_addr);
if((tp = strstr(rcpt_name, str)) != NULL && tp != rcpt_name) {
*tp = 0;
truncsp(rcpt_name);
}
}
smb_hfield_str(&newmsg, RECIPIENT, rcpt_name);
if(forward_path[0] != 0)
smb_hfield_str(&newmsg, SMTPFORWARDPATH, forward_path);

rswindell
committed
if(usernum && nettype!=NET_INTERNET) { /* Local destination or QWKnet routed */
/* This is required for fixsmb to be able to rebuild the index */
smb_hfield_str(&newmsg, RECIPIENTEXT, str);
}
if(nettype!=NET_NONE) {
smb_hfield(&newmsg, RECIPIENTNETTYPE, sizeof(nettype), &nettype);
smb_hfield_netaddr(&newmsg, RECIPIENTNETADDR, rcpt_addr, &nettype);

rswindell
committed
}
if(agent!=newmsg.to_agent)
smb_hfield(&newmsg, RECIPIENTAGENT, sizeof(agent), &agent);
i=smb_addmsghdr(&smb,&newmsg,smb_storage_mode(&scfg, &smb));

rswindell
committed
smb_freemsgmem(&newmsg);
if(i!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d %s !ERROR %d (%s) adding message header"
,socket, client.protocol, i, smb.last_error);

rswindell
committed
break;
sender_ext[0]=0;
if(msg.from_ext!=NULL)
SAFEPRINTF(sender_ext," #%s",msg.from_ext);
lprintf(LOG_INFO,"%04d %s Created message #%u from %s%s [%s] to %s [%s]"
,socket, client.protocol, newmsg.hdr.number, sender, sender_ext, smb_netaddrstr(&msg.from_net,tmp), rcpt_name, rcpt_addr);
if(relay_user.number!=0)
user_sent_email(&scfg, &relay_user, 1, usernum==1);
if(nettype == NET_FIDO && scfg.netmail_sem[0])
ftouch(mailcmdstr(scfg.netmail_sem
,msgtxt_fname, newtxt_fname, logtxt_fname
,rcptlst_fname, proc_err_fname
,host_name, host_ip, relay_user.number
,rcpt_addr
,sender, sender_addr, reverse_path, str));
if(!(startup->options&MAIL_OPT_NO_NOTIFY) && usernum) {
if(newmsg.idx.to)
for(i=1;i<=scfg.sys_nodes;i++) {
getnodedat(&scfg, i, &node, 0);
if(node.useron==usernum
&& (node.status==NODE_INUSE || node.status==NODE_QUIET))
break;
}
if(!newmsg.idx.to || i<=scfg.sys_nodes) {
p=sender_addr;
if(stricmp(sender, sender_addr) == 0) {
if((p = strchr(sender_addr, '@')) == NULL)
p = sender_addr;
else
p++;
}
safe_snprintf(str,sizeof(str)
,startup->newmail_notice
,timestr(&scfg,newmsg.hdr.when_imported.time,tmp)
,sender, p);
if(!newmsg.idx.to) /* Forwarding */
sprintf(str+strlen(str), startup->forward_notice, rcpt_addr);
putsmsg(&scfg, usernum, str);

rswindell
committed
}
iniFreeStringList(sec_list);
if(rcpt_count<1) {
smb_freemsg_dfields(&smb,&msg,SMB_ALL_REFS);
sockprintf(socket,client.protocol,session, insuf_stor);

rswindell
committed
}
else {
if(rcpt_count>1)
smb_incmsg_dfields(&smb,&msg,(ushort)(rcpt_count-1));
sockprintf(socket,client.protocol,session,ok_rsp);
signal_smtp_sem();
#if 0 /* This shouldn't be necessary here */
smb_close_da(&smb);
#endif
smb_close(&smb);
continue;
}
if(buf[0]==0 && state==SMTP_STATE_DATA_HEADER) {
state=SMTP_STATE_DATA_BODY; /* Null line separates header and body */
if(msgtxt!=NULL) {
fprintf(msgtxt, "\r\n");
hdr_len=ftell(msgtxt);
}
continue;
}
if(state==SMTP_STATE_DATA_BODY) {
p=buf;
if(*p=='.') p++; /* Transparency (RFC821 4.5.2) */
if(msgtxt!=NULL) {
switch(content_encoding) {
case ENCODING_BASE64:
{
char decode_buf[sizeof(buf)];
if(b64_decode(decode_buf, sizeof(decode_buf), p, strlen(p))<0)
fprintf(msgtxt,"\r\n!Base64 decode error: %s\r\n", p);
else
fputs(decode_buf, msgtxt);
}
break;
case ENCODING_QUOTED_PRINTABLE:
fputs(qp_decode(p), msgtxt);
break;
default:
fprintf(msgtxt, "%s\r\n", p);
break;
}