Newer
Older
p=alias(&scfg,p,alias_buf);
if(p==alias_buf)
lprintf(LOG_INFO,"%04d SMTP ADDRESS ALIAS: %s",socket,p);
tp=strrchr(p,'@');
if(cmd==SMTP_CMD_MAIL && tp!=NULL) {
dest_port=server_addr.sin_port;
cp=strrchr(dest_host,':');
if(cp!=NULL) {
*cp=0;
dest_port=atoi(cp+1);
}
sprintf(domain_list,"%sdomains.cfg",scfg.ctrl_dir);
if((stricmp(dest_host,scfg.sys_inetaddr)!=0
&& stricmp(dest_host,startup->host_name)!=0
&& resolve_ip(dest_host)!=server_addr.sin_addr.s_addr
&& findstr(dest_host,domain_list)==FALSE)
|| dest_port!=server_addr.sin_port) {
sprintf(relay_list,"%srelay.cfg",scfg.ctrl_dir);
if(relay_user.number==0 /* not authenticated, search for IP */
&& startup->options&MAIL_OPT_SMTP_AUTH_VIA_IP) {
relay_user.number=userdatdupe(&scfg, 0, U_NOTE, LEN_NOTE, host_ip, FALSE);
if(relay_user.number) {
getuserdat(&scfg,&relay_user);
if(relay_user.laston < time(NULL)-(60*60)) /* logon in past hour? */
relay_user.number=0;
}
} else
getuserdat(&scfg,&relay_user);
if(p!=alias_buf /* forced relay by alias */ &&
(!(startup->options&MAIL_OPT_ALLOW_RELAY)
|| relay_user.number==0
|| relay_user.rest&(FLAG('G')|FLAG('M'))) &&
!findstr(host_name,relay_list) &&
!findstr(host_ip,relay_list)) {
lprintf(LOG_WARNING,"%04d !SMTP ILLEGAL RELAY ATTEMPT from %s [%s] to %s"
,socket, reverse_path, host_ip, p);
SAFEPRINTF(tmp,"Relay attempt to: %s", p);
spamlog(&scfg, "SMTP", "REFUSED", tmp, host_name, host_ip, rcpt_addr, reverse_path);
if(startup->options&MAIL_OPT_ALLOW_RELAY)
sockprintf(socket, "553 Relaying through this server "
"requires authentication. "
"Please authenticate before sending.");
else
sockprintf(socket, "550 Relay not allowed.");
if(relay_user.number==0)
SAFECOPY(relay_user.alias,"Unknown User");
lprintf(LOG_INFO,"%04d SMTP %s relaying to external mail service: %s"
,socket, relay_user.alias, tp+1);
fprintf(rcptlst,"[%u]\n",rcpt_count++);
fprintf(rcptlst,"%s=%s\n",smb_hfieldtype(RECIPIENT),rcpt_addr);
fprintf(rcptlst,"%s=%u\n",smb_hfieldtype(RECIPIENTNETTYPE),NET_INTERNET);
fprintf(rcptlst,"%s=%s\n",smb_hfieldtype(RECIPIENTNETADDR),p);
sockprintf(socket,ok_rsp);
tp=strchr(p,'!'); /* Routed QWKnet mail in <qwkid!user@host> format */
if(tp!=NULL) {
*(tp++)=0;
SKIP_CHAR(tp,'"'); /* Skip '"' */
truncstr(tp,"\""); /* Strip '"' */
SAFECOPY(rcpt_addr,tp);
routed=TRUE;
FIND_ALPHANUMERIC(p); /* Skip '<' or '"' */
truncstr(p,"\"");
p=alias(&scfg,p,name_alias_buf);
if(p==name_alias_buf)
lprintf(LOG_INFO,"%04d SMTP NAME ALIAS: %s",socket,p);
if(!strnicmp(p,"sub:",4)) { /* Post on a sub-board */
p+=4;
for(i=0;i<scfg.total_subs;i++)
if(!stricmp(p,scfg.sub[i]->code))
break;
if(i>=scfg.total_subs) {
lprintf(LOG_WARNING,"%04d !SMTP UNKNOWN SUB-BOARD: %s", socket, p);
sockprintf(socket, "550 Unknown sub-board: %s", p);
continue;
}
subnum=i;
sockprintf(socket,ok_rsp);
state=SMTP_STATE_RCPT_TO;
rcpt_count++;
continue;
}
memset(mailproc_match,FALSE,sizeof(BOOL)*mailproc_count);
for(i=0;i<mailproc_count;i++) {
if(mailproc_list[i].to!=NULL) {
for(j=0;mailproc_list[i].to[j]!=NULL;j++) {
if(stricmp(p,mailproc_list[i].to[j])==0) {
mailproc_match[i]=TRUE;
if(!mailproc_list[i].passthru)
break;
}
}
}
}
/* destined for an external mail processor */
if(i<mailproc_count) {
fprintf(rcptlst,"[%u]\n",rcpt_count++);
fprintf(rcptlst,"%s=%s\n",smb_hfieldtype(RECIPIENT),rcpt_addr);
#if 0 /* should we fall-through to the sysop account? */
fprintf(rcptlst,"%s=%u\n",smb_hfieldtype(RECIPIENTEXT),1);
#endif
lprintf(LOG_INFO,"%04d SMTP Routing mail for %s to External Mail Processor: %s"
,socket, rcpt_addr, mailproc_list[i].cmdline);
sockprintf(socket,ok_rsp);
state=SMTP_STATE_RCPT_TO;
continue;
}
usernum=0; /* unknown user at this point */
if(routed) {
SAFECOPY(qwkid,p);
truncstr(qwkid,"/");
/* Search QWKnet hub-IDs for route destination */
for(i=0;i<scfg.total_qhubs;i++) {
if(!stricmp(qwkid,scfg.qhub[i]->id))
break;
}
if(i<scfg.total_qhubs) { /* found matching QWKnet Hub */
lprintf(LOG_INFO,"%04d SMTP Routing mail for %s <%s> to QWKnet Hub: %s"
,socket, rcpt_addr, p, scfg.qhub[i]->id);
fprintf(rcptlst,"[%u]\n",rcpt_count++);
fprintf(rcptlst,"%s=%s\n",smb_hfieldtype(RECIPIENT),rcpt_addr);
fprintf(rcptlst,"%s=%u\n",smb_hfieldtype(RECIPIENTNETTYPE),NET_QWK);
fprintf(rcptlst,"%s=%s\n",smb_hfieldtype(RECIPIENTNETADDR),p);
sockprintf(socket,ok_rsp);
state=SMTP_STATE_RCPT_TO;
continue;
}
}
if(startup->options&MAIL_OPT_ALLOW_RX_BY_NUMBER
usernum=atoi(p); /* RX by user number */
/* verify usernum */
username(&scfg,usernum,str);
if(!str[0] || !stricmp(str,"DELETED USER"))
usernum=0;
p=str;
} else {
/* RX by "user alias", "user.alias" or "user_alias" */
usernum=matchuser(&scfg,p,TRUE /* sysop_alias */);
if(!usernum) { /* RX by "real name", "real.name", or "sysop.alias" */
/* convert "user.name" to "user name" */
for(tp=rcpt_name;*tp;tp++)
if(*tp=='.') *tp=' ';
if(!stricmp(p,scfg.sys_op) || !stricmp(rcpt_name,scfg.sys_op))
usernum=1; /* RX by "sysop.alias" */
if(!usernum && scfg.msg_misc&MM_REALNAME) /* RX by "real name" */
usernum=userdatdupe(&scfg, 0, U_NAME, LEN_NAME, p, FALSE);
if(!usernum && scfg.msg_misc&MM_REALNAME) /* RX by "real.name" */
usernum=userdatdupe(&scfg, 0, U_NAME, LEN_NAME, rcpt_name, FALSE);
if(!usernum && startup->default_user[0]) {
usernum=matchuser(&scfg,startup->default_user,TRUE /* sysop_alias */);
lprintf(LOG_INFO,"%04d SMTP Forwarding mail for UNKNOWN USER to default user: %s"
,socket,startup->default_user);
else
lprintf(LOG_WARNING,"%04d !SMTP UNKNOWN DEFAULT USER: %s"
,socket,startup->default_user);
}
lprintf(LOG_WARNING,"%04d !SMTP UNKNOWN USER:%s", socket, buf+8);
sockprintf(socket, "550 Unknown User:%s", buf+8);
continue;
}
user.number=usernum;
if((i=getuserdat(&scfg, &user))!=0) {
lprintf(LOG_ERR,"%04d !SMTP ERROR %d getting data on user #%u (%s)"
sockprintf(socket, "550 Unknown User:%s", buf+8);
continue;
}
if(user.misc&(DELETED|INACTIVE)) {
lprintf(LOG_WARNING,"%04d !SMTP DELETED or INACTIVE user #%u (%s)"
sockprintf(socket, "550 Unknown User:%s", buf+8);
if(cmd==SMTP_CMD_SEND) { /* Check if user online */

rswindell
committed
for(i=0;i<scfg.sys_nodes;i++) {
getnodedat(&scfg, i+1, &node, 0);
if(node.status==NODE_INUSE && node.useron==user.number
&& !(node.misc&NODE_POFF))
break;
}
if(i>=scfg.sys_nodes) {
lprintf(LOG_WARNING,"%04d !Attempt to send telegram to unavailable user #%u (%s)"

rswindell
committed
,socket, user.number, user.alias);
sockprintf(socket,"450 User unavailable");
continue;
}
}

rswindell
committed
if(useron.etoday>=cfg.level_emailperday[useron.level]
&& !(useron.rest&FLAG('Q'))) {
bputs(text[TooManyEmailsToday]);
continue;
}

rswindell
committed
} else
telegram=TRUE;
fprintf(rcptlst,"[%u]\n",rcpt_count++);
fprintf(rcptlst,"%s=%s\n",smb_hfieldtype(RECIPIENT),rcpt_addr);
fprintf(rcptlst,"%s=%u\n",smb_hfieldtype(RECIPIENTEXT),user.number);
/* Forward to Internet */
tp=strrchr(user.netmail,'@');

rswindell
committed
if(!telegram
&& !no_forward

rswindell
committed
&& scfg.sys_misc&SM_FWDTONET
&& (user.misc&NETMAIL || forward)
&& tp!=NULL && smb_netaddr_type(user.netmail)==NET_INTERNET
&& !strstr(tp,scfg.sys_inetaddr)) {
lprintf(LOG_INFO,"%04d SMTP Forwarding to: %s"
fprintf(rcptlst,"%s=%u\n",smb_hfieldtype(RECIPIENTNETTYPE),NET_INTERNET);
fprintf(rcptlst,"%s=%s\n",smb_hfieldtype(RECIPIENTNETADDR),user.netmail);
sockprintf(socket,"251 User not local; will forward to %s", user.netmail);
} else { /* Local (no-forward) */
if(routed) { /* QWKnet */
fprintf(rcptlst,"%s=%u\n",smb_hfieldtype(RECIPIENTNETTYPE),NET_QWK);
fprintf(rcptlst,"%s=%s\n",smb_hfieldtype(RECIPIENTNETADDR),user.alias);
}
sockprintf(socket,ok_rsp);
}
/* Message Data (header and body) */
if(!strnicmp(buf,"DATA",4)) {
lprintf(LOG_WARNING,"%04d !SMTP MISSING 'RCPT TO' command", socket);
sockprintf(socket, badseq_rsp);
if(msgtxt!=NULL) {
fclose(msgtxt), msgtxt=NULL;
if(!(startup->options&MAIL_OPT_DEBUG_RX_BODY))
unlink(msgtxt_fname);
}
SAFEPRINTF2(msgtxt_fname,"%sSBBS_SMTP.%s.msg", scfg.temp_dir, session_id);
if((msgtxt=fopen(msgtxt_fname,"w+b"))==NULL) {
lprintf(LOG_ERR,"%04d !SMTP ERROR %d opening %s"
,socket, errno, msgtxt_fname);
sockprintf(socket, "452 Insufficient system storage");
continue;
}

rswindell
committed
/* These vars are potentially over-written by parsing an RFC822 header */
/* get sender_addr */
p=strchr(reverse_path,'<');
if(p==NULL)
p=reverse_path;
else
p++;
SAFECOPY(sender_addr,p);
truncstr(sender_addr,">");

rswindell
committed
/* get sender */
SAFECOPY(sender,sender_addr);
if(truncstr(sender,"@")==NULL)

rswindell
committed
sender[0]=0;
sockprintf(socket, "354 send the mail data, end with <CRLF>.<CRLF>");

rswindell
committed
if(telegram)
state=SMTP_STATE_DATA_BODY; /* No RFC headers in Telegrams */
else
state=SMTP_STATE_DATA_HEADER;
hdr_lines=0;
continue;
}
sockprintf(socket,"500 Syntax error");
lprintf(LOG_WARNING,"%04d !SMTP UNSUPPORTED COMMAND: '%s'", socket, buf);
lprintf(LOG_WARNING,"%04d !TOO MANY INVALID COMMANDS (%u)",socket,badcmds);
break;
}
}
/* Free up resources here */
smb_freemsgmem(&msg);
if(msgtxt!=NULL) {
fclose(msgtxt);
if(!(startup->options&MAIL_OPT_DEBUG_RX_BODY))
unlink(msgtxt_fname);
}
if(rcptlst!=NULL) {
fclose(rcptlst);
unlink(rcptlst_fname);
}
if(spy!=NULL)
fclose(spy);
status(STATUS_WFC);
if(active_clients)
active_clients--, update_clients();
client_off(socket);
thread_down();
lprintf(LOG_DEBUG,"%04d SMTP RX Session thread terminated (%u threads remain, %lu clients served)"
,socket, thread_count, served);
/* Must be last */
mail_close_socket(socket);
}
BOOL bounce(smb_t* smb, smbmsg_t* msg, char* err, BOOL immediate)
{
char str[128];
char attempts[64];
ushort agent=AGENT_SMTPSYSMSG;
msg->hdr.delivery_attempts++;
lprintf(LOG_WARNING,"0000 !Delivery attempt #%u FAILED (%s) for message #%lu from %s to %s"
,msg->hdr.delivery_attempts
,err
,msg->hdr.number
,msg->from
,msg->to_net.addr);
if((i=smb_updatemsg(smb,msg))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"0000 !BOUNCE ERROR %d (%s) incrementing delivery attempt counter"
,i, smb->last_error);
if(!immediate && msg->hdr.delivery_attempts < startup->max_delivery_attempts)
return(TRUE);
newmsg=*msg;
/* Mark original message as deleted */
msg->hdr.attr|=MSG_DELETE;
i=smb_updatemsg(smb,msg);
if(msg->hdr.auxattr&MSG_FILEATTACH)
delfattach(&scfg,msg);
if(i!=SMB_SUCCESS) {
lprintf(LOG_ERR,"0000 !BOUNCE ERROR %d (%s) deleting message"
,i, smb->last_error);
if(msg->from_agent!=AGENT_PERSON /* don't bounce 'bounce messages' */
|| (msg->idx.from==0 && msg->from_net.type==NET_NONE)
|| (msg->reverse_path!=NULL && *msg->reverse_path==0)) {
lprintf(LOG_WARNING,"0000 !Deleted undeliverable message from %s", msg->from);
return(TRUE);
}
lprintf(LOG_WARNING,"0000 !Bouncing message back to %s", msg->from);
newmsg.hfield=NULL;
newmsg.hfield_dat=NULL;
newmsg.total_hfields=0;
newmsg.hdr.delivery_attempts=0;
SAFEPRINTF(str,"Delivery failure: %s",newmsg.subj);
smb_hfield_str(&newmsg, SUBJECT, str);
smb_hfield_str(&newmsg, RECIPIENT, newmsg.from);
if(newmsg.from_ext!=NULL) { /* Back to sender */
smb_hfield_str(&newmsg, RECIPIENTEXT, newmsg.from_ext);
newmsg.from_ext=NULL; /* Clear the sender extension */
if((newmsg.from_net.type==NET_QWK || newmsg.from_net.type==NET_INTERNET)
&& newmsg.reverse_path!=NULL) {
smb_hfield(&newmsg, RECIPIENTNETTYPE, sizeof(newmsg.from_net.type), &newmsg.from_net.type);
smb_hfield_str(&newmsg, RECIPIENTNETADDR, newmsg.reverse_path);
}
strcpy(str,"Mail Delivery Subsystem");
smb_hfield_str(&newmsg, SENDER, str);
smb_hfield(&newmsg, SENDERAGENT, sizeof(agent), &agent);
/* Put error message in subject for now */
if(msg->hdr.delivery_attempts>1)
sprintf(attempts,"after %u attempts", msg->hdr.delivery_attempts);
else
attempts[0]=0;
SAFEPRINTF2(str,"%s reporting delivery failure of message %s"
,startup->host_name, attempts);
smb_hfield_str(&newmsg, SMB_COMMENT, str);
SAFEPRINTF2(str,"from %s to %s\r\n"
,msg->reverse_path==NULL ? msg->from : msg->reverse_path
,(char*)msg->to_net.addr);
smb_hfield_str(&newmsg, SMB_COMMENT, str);
strcpy(str,"Reason:");
smb_hfield_str(&newmsg, SMB_COMMENT, str);
smb_hfield_str(&newmsg, SMB_COMMENT, err);
smb_hfield_str(&newmsg, SMB_COMMENT, "\r\nOriginal message text follows:\r\n");
if((i=smb_addmsghdr(smb,&newmsg,SMB_SELFPACK))!=SMB_SUCCESS)
lprintf(LOG_ERR,"0000 !BOUNCE ERROR %d (%s) adding message header"
,i,smb->last_error);
else {
lprintf(LOG_WARNING,"0000 !Delivery failure notification (message #%ld) created for %s"
,newmsg.hdr.number, newmsg.from);
if((i=smb_incmsg_dfields(smb,&newmsg,1))!=SMB_SUCCESS)
lprintf(LOG_ERR,"0000 !BOUNCE ERROR %d (%s) incrementing data allocation units"
,i,smb->last_error);
}
newmsg.dfield=NULL; /* Don't double-free the data fields */
newmsg.hdr.total_dfields=0;
smb_freemsgmem(&newmsg);
return(TRUE);
}
static int remove_msg_intransit(smb_t* smb, smbmsg_t* msg)
{
int i;
if((i=smb_lockmsghdr(smb,msg))!=SMB_SUCCESS) {
lprintf(LOG_WARNING,"0000 !SEND ERROR %d (%s) locking message header #%lu"
,i, smb->last_error, msg->idx.number);
return(i);
}
msg->hdr.netattr&=~MSG_INTRANSIT;
i=smb_putmsghdr(smb,msg);
smb_unlockmsghdr(smb,msg);
if(i!=0)
lprintf(LOG_ERR,"0000 !SEND ERROR %d (%s) writing message header #%lu"
,i, smb->last_error, msg->idx.number);
return(i);
}
void get_dns_server(char* dns_server, size_t len)
{
str_list_t list;
size_t count;
sprintf(dns_server,"%.*s",len,startup->dns_server);
if(!isalnum(dns_server[0])) {
if((list=getNameServerList())!=NULL) {
if((count=strListCount(list))>0) {
sprintf(dns_server,"%.*s",len,list[xp_random(count)]);
lprintf(LOG_DEBUG,"0000 SEND using auto-detected DNS server address: %s"
,dns_server);
}
freeNameServerList(list);
}
}
}
#ifdef __BORLANDC__
#pragma argsused
#endif
static void sendmail_thread(void* arg)
{
int i,j;
char to[128];
char mx[128];
char mx2[128];
char str[128];
char resp[512];
char toaddr[256];
char challenge[256];
char secret[64];
char md5_data[384];
char digest[MD5_DIGEST_SIZE];
char numeric_ip[16];
char domain_list[MAX_PATH+1];
char dns_server[16];
char* server;
char* msgtxt=NULL;
char* p;
char* tp;
ushort port;
ulong last_msg=0;
ulong ip_addr;
ulong dns;
BOOL first_cycle=TRUE;
SOCKET sock=INVALID_SOCKET;
SOCKADDR_IN addr;
SOCKADDR_IN server_addr;
time_t last_scan=0;
smb_t smb;
smbmsg_t msg;
mail_t* mail;
long msgs;
long l;
BOOL sending_locally=FALSE;
SetThreadName("SendMail Thread");
thread_up(TRUE /* setuid */);
sendmail_running=TRUE;
terminate_sendmail=FALSE;
lprintf(LOG_DEBUG,"0000 SendMail thread started");
memset(&msg,0,sizeof(msg));
memset(&smb,0,sizeof(smb));
while(server_socket!=INVALID_SOCKET && !terminate_sendmail) {
if(startup->options&MAIL_OPT_NO_SENDMAIL) {
sem_trywait_block(&sendmail_wakeup_sem,1000);
continue;
}
if(active_sendmail!=0)
active_sendmail=0, update_clients();
smb_close(&smb);
if(sock!=INVALID_SOCKET) {

rswindell
committed
mail_close_socket(sock);
sock=INVALID_SOCKET;
}
if(msgtxt!=NULL) {
smb_freemsgtxt(msgtxt);
msgtxt=NULL;
}
smb_freemsgmem(&msg);
/* Don't delay on first loop */
if(first_cycle)
first_cycle=FALSE;
else
sem_trywait_block(&sendmail_wakeup_sem,startup->sem_chk_freq*1000);

rswindell
committed
sprintf(smb.file,"%smail",scfg.data_dir);
smb.retry_time=scfg.smb_retry_time;
smb.subnum=INVALID_SUB;
if((i=smb_open(&smb))!=SMB_SUCCESS)
if((i=smb_locksmbhdr(&smb))!=SMB_SUCCESS)
i=smb_getstatus(&smb);
if(i!=0)
continue;
if(smb.status.last_msg==last_msg && time(NULL)-last_scan<startup->rescan_frequency)
continue;
last_msg=smb.status.last_msg;
last_scan=time(NULL);
mail=loadmail(&smb,&msgs,/* to network */0,MAIL_YOUR,0);
for(l=0; l<msgs; l++) {
if(active_sendmail!=0)
active_sendmail=0, update_clients();
if(server_socket==INVALID_SOCKET || terminate_sendmail) /* server stopped */

rswindell
committed
mail_close_socket(sock);
sock=INVALID_SOCKET;
}
if(msgtxt!=NULL) {
smb_freemsgtxt(msgtxt);
msgtxt=NULL;
}
smb_freemsgmem(&msg);
msg.hdr.number=mail[l].number;
if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"0000 !SEND ERROR %d (%s) getting message index #%lu"
,i, smb.last_error, mail[l].number);
if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_WARNING,"0000 !SEND ERROR %d (%s) locking message header #%lu"
,i, smb.last_error, msg.idx.number);
if((i=smb_getmsghdr(&smb,&msg))!=SMB_SUCCESS) {
smb_unlockmsghdr(&smb,&msg);
lprintf(LOG_ERR,"0000 !SEND ERROR %d (%s) reading message header #%lu"
,i, smb.last_error, msg.idx.number);
if(msg.hdr.attr&MSG_DELETE || msg.to_net.type!=NET_INTERNET || msg.to_net.addr==NULL) {
smb_unlockmsghdr(&smb,&msg);
if(!(startup->options&MAIL_OPT_SEND_INTRANSIT) && msg.hdr.netattr&MSG_INTRANSIT) {
smb_unlockmsghdr(&smb,&msg);
lprintf(LOG_ERR,"0000 SEND Message #%lu from %s to %s - in transit"
,msg.hdr.number, msg.from, msg.to_net.addr);
continue;
}
msg.hdr.netattr|=MSG_INTRANSIT; /* Prevent another sendmail thread from sending this msg */
smb_putmsghdr(&smb,&msg);
smb_unlockmsghdr(&smb,&msg);
active_sendmail=1, update_clients();
lprintf(LOG_INFO,"0000 SEND Message #%lu from %s to %s"
,msg.hdr.number, msg.from, msg.to_net.addr);
if(startup->outbound_sound[0] && !(startup->options&MAIL_OPT_MUTE))
PlaySound(startup->outbound_sound, NULL, SND_ASYNC|SND_FILENAME);
lprintf(LOG_DEBUG,"0000 SEND getting message text");
if((msgtxt=smb_getmsgtxt(&smb,&msg,GETMSGTXT_ALL))==NULL) {
remove_msg_intransit(&smb,&msg);
lprintf(LOG_ERR,"0000 !SEND ERROR (%s) retrieving message text",smb.last_error);
port=0;
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
/* Check if this is a local email ToDo */
SAFECOPY(to,(char*)msg.to_net.addr);
truncstr(to,"> ");
p=strrchr(to,'@');
if(p==NULL) {
remove_msg_intransit(&smb,&msg);
lprintf(LOG_WARNING,"0000 !SEND INVALID destination address: %s", to);
SAFEPRINTF(err,"Invalid destination address: %s", to);
bounce(&smb,&msg,err,TRUE);
continue;
}
p++;
sprintf(domain_list,"%sdomains.cfg",scfg.ctrl_dir);
if(stricmp(p,scfg.sys_inetaddr)==0
|| stricmp(p,startup->host_name)==0
|| findstr(p,domain_list)) {
/* This is a local message... no need to send to remote */
port = startup->smtp_port;
if(startup->interface_addr==0)
server="127.0.0.1";
else {
sprintf(numeric_ip, "%u.%u.%u.%u"
, startup->interface_addr >> 24
, (startup->interface_addr >> 16) & 0xff
, (startup->interface_addr >> 8) & 0xff
, startup->interface_addr & 0xff);
server = numeric_ip;
sending_locally=TRUE;
}
else {
if(startup->options&MAIL_OPT_RELAY_TX) {
server=startup->relay_server;
port=startup->relay_port;
} else {
server=p;
tp=strrchr(p,':'); /* non-standard SMTP port */
if(tp!=NULL) {
*tp=0;
port=atoi(tp+1);
if(port==0) { /* No port specified, use MX look-up */
get_dns_server(dns_server,sizeof(dns_server));
if((dns=resolve_ip(dns_server))==INADDR_NONE) {
remove_msg_intransit(&smb,&msg);
lprintf(LOG_WARNING,"0000 !SEND INVALID DNS server address: %s"
,dns_server);
continue;
}
lprintf(LOG_DEBUG,"0000 SEND getting MX records for %s from %s",p,dns_server);
if((i=dns_getmx(p, mx, mx2, startup->interface_addr, dns
,startup->options&MAIL_OPT_USE_TCP_DNS ? TRUE : FALSE
,TIMEOUT_THREAD_WAIT/2))!=0) {
remove_msg_intransit(&smb,&msg);
lprintf(LOG_WARNING,"0000 !SEND ERROR %d obtaining MX records for %s from %s"
,i,p,startup->dns_server);
SAFEPRINTF2(err,"Error %d obtaining MX record for %s",i,p);
bounce(&smb,&msg,err,FALSE);
continue;
}
server=mx;
if(!port)
port=IPPORT_SMTP;
if((sock=mail_open_socket(SOCK_STREAM,"smtp|sendmail"))==INVALID_SOCKET) {
remove_msg_intransit(&smb,&msg);
lprintf(LOG_ERR,"0000 !SEND ERROR %d opening socket", ERROR_VALUE);
continue;
}
memset(&addr,0,sizeof(addr));
addr.sin_addr.s_addr = htonl(startup->interface_addr);
addr.sin_family = AF_INET;
if(startup->seteuid!=NULL)
startup->seteuid(FALSE);
i=bind(sock,(struct sockaddr *)&addr, sizeof(addr));
if(startup->seteuid!=NULL)
startup->seteuid(TRUE);
remove_msg_intransit(&smb,&msg);
lprintf(LOG_ERR,"%04d !SEND ERROR %d (%d) binding socket", sock, i, ERROR_VALUE);
continue;
}
strcpy(err,"UNKNOWN ERROR");
success=FALSE;
for(j=0;j<2 && !success;j++) {
if(j) {
if(startup->options&MAIL_OPT_RELAY_TX || !mx2[0])
break;
server=mx2; /* Give second mx record a try */
}
lprintf(LOG_DEBUG,"%04d SEND resolving SMTP hostname: %s", sock, server);
ip_addr=resolve_ip(server);
if(ip_addr==INADDR_NONE) {
SAFEPRINTF(err,"Failed to resolve SMTP hostname: %s",server);
continue;
}
memset(&server_addr,0,sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
if((server==mx || server==mx2)
&& ((ip_addr&0xff)==127 || ip_addr==0)) {
SAFEPRINTF2(err,"Bad IP address (%s) for MX server: %s"
,inet_ntoa(server_addr.sin_addr),server);
continue;
}
lprintf(LOG_INFO,"%04d SEND connecting to port %u on %s [%s]"

rswindell
committed
,ntohs(server_addr.sin_port)
,server,inet_ntoa(server_addr.sin_addr));
if((i=connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)))!=0) {
lprintf(LOG_WARNING,"%04d !SEND ERROR %d connecting to SMTP server: %s"
SAFEPRINTF2(err,"Error %d connecting to SMTP server: %s"
continue;
}
success=TRUE;
}
if(!success) { /* Failed to send, so bounce */
remove_msg_intransit(&smb,&msg);
bounce(&smb,&msg,err,FALSE);
continue;
}
lprintf(LOG_DEBUG,"%04d SEND connected to %s",sock,server);
/* HELO */
if(!sockgetrsp(sock,"220",buf,sizeof(buf))) {
remove_msg_intransit(&smb,&msg);
SAFEPRINTF3(err,badrsp_err,server,buf,"220");
bounce(&smb,&msg,err,buf[0]=='5');
continue;
}
if(startup->options&MAIL_OPT_RELAY_TX
&& (startup->options&MAIL_OPT_RELAY_AUTH_MASK)!=0) /* Requires ESMTP */
sockprintf(sock,"EHLO %s",startup->host_name);
else
sockprintf(sock,"HELO %s",startup->host_name);
if(!sockgetrsp(sock,"250", buf, sizeof(buf))) {
remove_msg_intransit(&smb,&msg);
SAFEPRINTF3(err,badrsp_err,server,buf,"250");
bounce(&smb,&msg,err,buf[0]=='5');
continue;
}
/* AUTH */
if(startup->options&MAIL_OPT_RELAY_TX
&& (startup->options&MAIL_OPT_RELAY_AUTH_MASK)!=0 && !sending_locally) {
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
switch(startup->options&MAIL_OPT_RELAY_AUTH_MASK) {
case MAIL_OPT_RELAY_AUTH_PLAIN:
p="PLAIN";
break;
case MAIL_OPT_RELAY_AUTH_LOGIN:
p="LOGIN";
break;
case MAIL_OPT_RELAY_AUTH_CRAM_MD5:
p="CRAM-MD5";
break;
default:
p="<unknown>";
break;
}
sockprintf(sock,"AUTH %s",p);
if(!sockgetrsp(sock,"334",buf,sizeof(buf))) {
SAFEPRINTF3(err,badrsp_err,server,buf,"334 Username/Challenge");
bounce(&smb,&msg,err,buf[0]=='5');
continue;
}
switch(startup->options&MAIL_OPT_RELAY_AUTH_MASK) {
case MAIL_OPT_RELAY_AUTH_PLAIN:
p=startup->relay_user;
break;
case MAIL_OPT_RELAY_AUTH_LOGIN:
b64_encode(p=resp,sizeof(resp),startup->relay_user,0);
break;
case MAIL_OPT_RELAY_AUTH_CRAM_MD5:
p=buf;
FIND_WHITESPACE(p);
SKIP_WHITESPACE(p);
b64_decode(challenge,sizeof(challenge),p,0);
/* Calculate response */
memset(secret,0,sizeof(secret));
SAFECOPY(secret,startup->relay_pass);
for(i=0;i<sizeof(secret);i++)
md5_data[i]=secret[i]^0x36; /* ipad */
strcpy(md5_data+i,challenge);
MD5_calc(digest,md5_data,sizeof(secret)+strlen(challenge));
for(i=0;i<sizeof(secret);i++)
md5_data[i]=secret[i]^0x5c; /* opad */
memcpy(md5_data+i,digest,sizeof(digest));
MD5_calc(digest,md5_data,sizeof(secret)+sizeof(digest));
safe_snprintf(buf,sizeof(buf),"%s %s",startup->relay_user,MD5_hex(str,digest));
b64_encode(p=resp,sizeof(resp),buf,0);
break;
default:
p="<unknown>";
break;
}
sockprintf(sock,"%s",p);
if((startup->options&MAIL_OPT_RELAY_AUTH_MASK)!=MAIL_OPT_RELAY_AUTH_CRAM_MD5) {
if(!sockgetrsp(sock,"334",buf,sizeof(buf))) {
SAFEPRINTF3(err,badrsp_err,server,buf,"334 Password");
bounce(&smb,&msg,err,buf[0]=='5');
continue;
}
switch(startup->options&MAIL_OPT_RELAY_AUTH_MASK) {
case MAIL_OPT_RELAY_AUTH_PLAIN:
p=startup->relay_pass;
break;
case MAIL_OPT_RELAY_AUTH_LOGIN:
b64_encode(p=buf,sizeof(buf),startup->relay_pass,0);
break;
default:
p="<unknown>";
break;
}
sockprintf(sock,"%s",p);
}
if(!sockgetrsp(sock,"235",buf,sizeof(buf))) {
SAFEPRINTF3(err,badrsp_err,server,buf,"235");
bounce(&smb,&msg,err,buf[0]=='5');
continue;
}
}
if(msg.from_net.type==NET_INTERNET && msg.reverse_path!=NULL)
SAFECOPY(fromaddr,msg.reverse_path);
usermailaddr(&scfg,fromaddr,msg.from);
truncstr(fromaddr," ");
if(fromaddr[0]=='<')
sockprintf(sock,"MAIL FROM: %s",fromaddr);
else
sockprintf(sock,"MAIL FROM: <%s>",fromaddr);
if(!sockgetrsp(sock,"250", buf, sizeof(buf))) {
remove_msg_intransit(&smb,&msg);
SAFEPRINTF3(err,badrsp_err,server,buf,"250");
bounce(&smb,&msg,err,buf[0]=='5');
continue;
}
/* RCPT */
if(msg.forward_path!=NULL) {
SAFECOPY(toaddr,msg.forward_path);
} else {
if((p=strrchr((char*)msg.to_net.addr,'<'))!=NULL)
p++;
else
p=(char*)msg.to_net.addr;
SAFECOPY(toaddr,p);
truncstr(toaddr,"> ");
if((p=strrchr(toaddr,'@'))!=NULL && (tp=strrchr(toaddr,':'))!=NULL
&& tp > p)
*tp=0; /* Remove ":port" designation from envelope */
}
sockprintf(sock,"RCPT TO: <%s>", toaddr);
if(!sockgetrsp(sock,"25", buf, sizeof(buf))) {
remove_msg_intransit(&smb,&msg);
SAFEPRINTF3(err,badrsp_err,server,buf,"25*");
bounce(&smb,&msg,err,buf[0]=='5');
continue;
}
/* DATA */
sockprintf(sock,"DATA");
if(!sockgetrsp(sock,"354", buf, sizeof(buf))) {
remove_msg_intransit(&smb,&msg);
SAFEPRINTF3(err,badrsp_err,server,buf,"354");
bounce(&smb,&msg,err,buf[0]=='5');
continue;
}
lprintf(LOG_DEBUG,"%04d SEND sending message text (%u bytes)"
lines=sockmsgtxt(sock,&msg,msgtxt,-1);
if(!sockgetrsp(sock,"250", buf, sizeof(buf))) {
remove_msg_intransit(&smb,&msg);
SAFEPRINTF3(err,badrsp_err,server,buf,"250");
bounce(&smb,&msg,err,buf[0]=='5');
continue;
}
lprintf(LOG_DEBUG,"%04d SEND message transfer complete (%lu lines)", sock, lines);
/* Now lets mark this message for deletion without corrupting the index */
msg.hdr.attr|=MSG_DELETE;
msg.hdr.netattr&=~MSG_INTRANSIT;
if((i=smb_updatemsg(&smb,&msg))!=SMB_SUCCESS)
lprintf(LOG_ERR,"%04d !SEND ERROR %d (%s) deleting message #%lu"
,sock, i, smb.last_error, msg.hdr.number);
if(msg.hdr.auxattr&MSG_FILEATTACH)
delfattach(&scfg,&msg);
/* QUIT */
sockprintf(sock,"QUIT");
sockgetrsp(sock,"221", buf, sizeof(buf));

rswindell
committed
mail_close_socket(sock);
sock=INVALID_SOCKET;
}
status(STATUS_WFC);
/* Free up resources here */
if(mail!=NULL)
freemail(mail);
}
if(sock!=INVALID_SOCKET)

rswindell
committed
mail_close_socket(sock);
smb_freemsgtxt(msgtxt);
smb_freemsgmem(&msg);
smb_close(&smb);
if(active_sendmail!=0)
active_sendmail=0, update_clients();
thread_down();
lprintf(LOG_DEBUG,"0000 SendMail thread terminated (%u threads remain)", thread_count);
sendmail_running=FALSE;
}
void DLLCALL mail_terminate(void)
lprintf(LOG_DEBUG,"%04d Mail Server terminate",server_socket);
terminate_server=TRUE;
}
static void cleanup(int code)