Newer
Older
lprintf(LOG_DEBUG,"%04d RX: %s",socket,buf);
if(b64_decode(response,sizeof(response),buf,rd)<1) {
lprintf(LOG_WARNING,"%04d !SMTP bad AUTH CRAM-MD5 response", socket);
sockprintf(socket,session,badarg_rsp);
continue;
}
#if 0
lprintf(LOG_DEBUG,"%04d SMTP CRAM-MD5 response: %s"
,socket,response);
if((p=strrchr(response,' '))!=NULL)
*(p++)=0;
else
p=response;
SAFECOPY(user_name,response);
if((relay_user.number=matchuser(&scfg,user_name,FALSE))==0) {

rswindell
committed
lprintf(LOG_WARNING,"%04d !SMTP UNKNOWN USER: '%s'"
,socket, user_name);
badlogin(socket, session, client.protocol, badauth_rsp, user_name, NULL, host_name, &smtp.client_addr);
break;
}
if((i=getuserdat(&scfg, &relay_user))!=0) {
lprintf(LOG_ERR,"%04d !SMTP ERROR %d getting data on user (%s)"
,socket, i, user_name);
badlogin(socket, session, client.protocol, badauth_rsp, NULL, NULL, NULL, NULL);
break;
}
if(relay_user.misc&(DELETED|INACTIVE)) {
lprintf(LOG_WARNING,"%04d !SMTP DELETED or INACTIVE user #%u (%s)"
,socket, relay_user.number, user_name);
badlogin(socket, session, client.protocol, badauth_rsp, NULL, NULL, NULL, NULL);
break;
}
/* Calculate correct response */
memset(secret,0,sizeof(secret));
SAFECOPY(secret,relay_user.pass);
strlwr(secret); /* this is case sensitive, so convert to lowercase first */
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));
MD5_hex((BYTE*)str,digest);
if(strcmp(p,str)) {
lprintf(LOG_WARNING,"%04d !SMTP %s FAILED CRAM-MD5 authentication"
,socket,relay_user.alias);
lprintf(LOG_DEBUG,"%04d !SMTP calc digest: %s"
,socket,str);
lprintf(LOG_DEBUG,"%04d !SMTP resp digest: %s"
,socket,p);
badlogin(socket, session, client.protocol, badauth_rsp, user_name, p, host_name, &smtp.client_addr);
break;
}
if(relay_user.pass[0])
loginSuccess(startup->login_attempt_list, &smtp.client_addr);
/* Update client display */
client.user=relay_user.alias;
client_on(socket,&client,TRUE /* update */);
lprintf(LOG_INFO,"%04d SMTP %s authenticated using CRAM-MD5 authentication"
,socket,relay_user.alias);
continue;
}
if(!strnicmp(buf,"AUTH",4)) {
sockprintf(socket,session,"504 Unrecognized authentication type.");
continue;
}
sockprintf(socket,session,"221 %s Service closing transmission channel",startup->host_name);
break;
}
if(!stricmp(buf,"NOOP")) {
badcmds=0;
continue;
}
if(state<SMTP_STATE_HELO) {
/* RFC 821 4.1.1 "The first command in a session must be the HELO command." */
lprintf(LOG_WARNING,"%04d !SMTP MISSING 'HELO' command (Received: '%s')",socket, buf);
sockprintf(socket,session, badseq_rsp);
continue;
}
if(!stricmp(buf,"TURN")) {
sockprintf(socket,session,"502 command not supported");
badcmds=0;
continue;
}
if(!stricmp(buf,"RSET")) {
smb_freemsgmem(&msg);
memset(&msg,0,sizeof(smbmsg_t)); /* Initialize message header */
reverse_path[0]=0;
state=SMTP_STATE_HELO;

rswindell
committed
telegram=FALSE;
subnum=INVALID_SUB;
/* reset recipient list */
if((rcptlst=freopen(rcptlst_fname,"w+",rcptlst))==NULL) {
lprintf(LOG_ERR,"%04d !SMTP ERROR %d re-opening %s"
,socket, errno, rcptlst_fname);
sockprintf(socket,session,sys_error);
break;
}
rcpt_count=0;
content_encoding=ENCODING_NONE;
memset(mailproc_to_match,FALSE,sizeof(BOOL)*mailproc_count);
badcmds=0;
lprintf(LOG_INFO,"%04d SMTP Session reset",socket);
if(!strnicmp(buf,"MAIL FROM:",10)
|| !strnicmp(buf,"SEND FROM:",10) /* Send a Message (Telegram) to a local ONLINE user */
|| !strnicmp(buf,"SOML FROM:",10) /* Send OR Mail a Message to a local user */
|| !strnicmp(buf,"SAML FROM:",10) /* Send AND Mail a Message to a local user */
) {
if(relay_user.number==0
&& !chk_email_addr(socket,p,host_name,host_ip,NULL,NULL,"REVERSE PATH")) {
sockprintf(socket,session, "554 Sender not allowed.");
}
SKIP_WHITESPACE(p);
if((p=strchr(reverse_path,' '))!=NULL) /* Truncate "<user@domain> KEYWORD=VALUE" to just "<user@domain>" per RFC 1869 */
*p=0;
/* If MAIL FROM address is in dnsbl_exempt.cfg, clear DNSBL results */
if(dnsbl_result.s_addr && email_addr_is_exempt(reverse_path)) {
lprintf(LOG_INFO,"%04d SMTP Ignoring DNSBL results for exempt sender: %s"
,socket,reverse_path);
dnsbl_result.s_addr=0;
}
/* Update client display */
if(relay_user.number==0) {
client.user=reverse_path;
client_on(socket,&client,TRUE /* update */);
}
/* Setup state */
if(!strnicmp(buf,"MAIL FROM:",10))
cmd=SMTP_CMD_MAIL;
else if(!strnicmp(buf,"SEND FROM:",10))
cmd=SMTP_CMD_SEND;
else if(!strnicmp(buf,"SOML FROM:",10))
cmd=SMTP_CMD_SOML;
else if(!strnicmp(buf,"SAML FROM:",10))
cmd=SMTP_CMD_SAML;
/* reset recipient list */
if((rcptlst=freopen(rcptlst_fname,"w+",rcptlst))==NULL) {
lprintf(LOG_ERR,"%04d !SMTP ERROR %d re-opening %s"
,socket, errno, rcptlst_fname);
sockprintf(socket,session,sys_error);
break;
}
rcpt_count=0;
content_encoding=ENCODING_NONE;
memset(mailproc_to_match,FALSE,sizeof(BOOL)*mailproc_count);
badcmds=0;

rswindell
committed
continue;
}
#if 0 /* No one uses this command */
if(!strnicmp(buf,"VRFY",4)) {
p=buf+4;
SKIP_WHITESPACE(p);
sockprintf(socket,session,"550 No user specified.");
continue;
}
#endif
/* Add to Recipient list */
if(!strnicmp(buf,"RCPT TO:",8)) {
lprintf(LOG_WARNING,"%04d !SMTP MISSING 'MAIL' command",socket);
sockprintf(socket,session, badseq_rsp);
SKIP_WHITESPACE(p);
p=strrchr(str,'<');
if(p==NULL)
p=str;
else
p++;
truncstr(str,">"); /* was truncating at space too */
routed=FALSE;
forward=FALSE;
no_forward=FALSE;
if(!strnicmp(p,FORWARD,strlen(FORWARD))) {
forward=TRUE; /* force forward to user's netmail address */
p+=strlen(FORWARD);
}
if(!strnicmp(p,NO_FORWARD,strlen(NO_FORWARD))) {
no_forward=TRUE; /* do not forward to user's netmail address */
p+=strlen(NO_FORWARD);
}
if(*p==0) {
lprintf(LOG_NOTICE,"%04d !SMTP NO RECIPIENT SPECIFIED"
sockprintf(socket,session, "500 No recipient specified");
continue;
}
rcpt_name[0]=0;
/* Check recipient counter */
if(startup->max_recipients) {
if(rcpt_count>=startup->max_recipients) {
lprintf(LOG_NOTICE,"%04d !SMTP MAXIMUM RECIPIENTS (%d) REACHED"
,socket, startup->max_recipients);
SAFEPRINTF(tmp,"Maximum recipient count (%d)",startup->max_recipients);
spamlog(&scfg, "SMTP", "REFUSED", tmp
,host_name, host_ip, rcpt_addr, reverse_path);
sockprintf(socket,session, "452 Too many recipients");
stats.msgs_refused++;
continue;
}
if(relay_user.number!=0 && !(relay_user.exempt&FLAG('M'))
&& rcpt_count+(waiting=getmail(&scfg,relay_user.number,/* sent: */TRUE, /* SPAM: */FALSE)) > startup->max_recipients) {
lprintf(LOG_NOTICE,"%04d !SMTP MAXIMUM PENDING SENT EMAILS (%u) REACHED for User #%u (%s)"
,socket, waiting, relay_user.number, relay_user.alias);
sockprintf(socket,session, "452 Too many pending emails sent");
if(relay_user.number && (relay_user.etoday+rcpt_count) >= scfg.level_emailperday[relay_user.level]
&& !(relay_user.exempt&FLAG('M'))) {
lprintf(LOG_NOTICE,"%04d !SMTP EMAILS PER DAY LIMIT (%u) REACHED FOR USER #%u (%s)"
,socket, scfg.level_emailperday[relay_user.level], relay_user.number, relay_user.alias);
SAFEPRINTF2(tmp,"Maximum emails per day (%u) for %s"
,scfg.level_emailperday[relay_user.level], relay_user.alias);
spamlog(&scfg, "SMTP", "REFUSED", tmp
,host_name, host_ip, rcpt_addr, reverse_path);
sockprintf(socket,session, "452 Too many emails today");
/* Check for SPAM bait recipient */
if((spam_bait_result=findstr(rcpt_addr,spam_bait))==TRUE) {
char reason[256];
SAFEPRINTF(reason,"SPAM BAIT (%s) taken", rcpt_addr);
lprintf(LOG_NOTICE,"%04d SMTP %s by: %s"
,socket, reason, reverse_path);
strcpy(tmp,"IGNORED");
if(dnsbl_result.s_addr==0 /* Don't double-filter */
lprintf(LOG_NOTICE,"%04d !BLOCKING IP ADDRESS: %s in %s", socket, host_ip, spam_block);
filter_ip(&scfg, "SMTP", reason, host_name, host_ip, reverse_path, spam_block);
strcat(tmp," and BLOCKED");
}
spamlog(&scfg, "SMTP", tmp, "Attempted recipient in SPAM BAIT list"
,host_name, host_ip, rcpt_addr, reverse_path);
dnsbl_result.s_addr=0;
}
state=SMTP_STATE_RCPT_TO;
continue;
}
/* Check for blocked recipients */
if(relay_user.number==0
&& !chk_email_addr(socket,rcpt_addr,host_name,host_ip,rcpt_addr,reverse_path,"RECIPIENT")) {
sockprintf(socket,session, "550 Unknown User: %s", rcpt_to);
continue;
}
if(relay_user.number==0 && dnsbl_result.s_addr && startup->options&MAIL_OPT_DNSBL_BADUSER) {
lprintf(LOG_NOTICE,"%04d !SMTP REFUSED MAIL from blacklisted server (%u total)"
,socket, ++stats.sessions_refused);
SAFEPRINTF2(str,"Listed on %s as %s", dnsbl, inet_ntoa(dnsbl_result));
spamlog(&scfg, "SMTP", "REFUSED", str, host_name, host_ip, rcpt_addr, reverse_path);
,"550 Mail from %s refused due to listing at %s"
,host_ip, dnsbl);
break;
}
if(spy==NULL
&& (trashcan(&scfg,reverse_path,"smtpspy")
|| trashcan(&scfg,rcpt_addr,"smtpspy"))) {
SAFEPRINTF(path,"%ssmtpspy.txt", scfg.logs_dir);
spy=fopen(path,"a");
}
/* Check for full address aliases */
p=alias(&scfg,p,alias_buf);
if(p==alias_buf)
lprintf(LOG_DEBUG,"%04d SMTP ADDRESS ALIAS: %s (for %s)"
,socket,p,rcpt_addr);
tp=strrchr(p,'@');
if(cmd==SMTP_CMD_MAIL && tp!=NULL) {
if(relay_user.number && scfg.total_faddrs) {
char* ftn_tld = strstr(dest_host, FIDO_TLD);
if(ftn_tld != NULL && ftn_tld[strlen(FIDO_TLD)] == 0) {
short point, node, net, zone;
,&point
,&node
,&net
,&zone)==4
,&node
,&net
,&zone)==3
) && zone) {
faddr.point = point;
faddr.node = node;
faddr.net = net;
faddr.zone = zone;
lprintf(LOG_INFO,"%04d SMTP %s relaying to FidoNet address: %s (%s)"
,socket, relay_user.alias, tp+1, smb_faddrtoa(&faddr, NULL));
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_FIDO);
fprintf(rcptlst,"%s=%s\n",smb_hfieldtype(RECIPIENTNETADDR),smb_faddrtoa(&faddr,NULL));
state=SMTP_STATE_RCPT_TO;
continue;
}
}
}
cp=strrchr(dest_host,':');
if(cp!=NULL) {
*cp=0;
dest_port=atoi(cp+1);
}
SAFEPRINTF(domain_list,"%sdomains.cfg",scfg.ctrl_dir);
if((stricmp(dest_host,scfg.sys_inetaddr)!=0
&& stricmp(dest_host,startup->host_name)!=0
&& findstr(dest_host,domain_list)==FALSE)
SAFEPRINTF(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_IPADDR, LEN_IPADDR, host_ip, /* del */FALSE, /* next */FALSE, NULL, NULL);
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,session, "553 Relaying through this server "
"requires authentication. "
"Please authenticate before sending.");
else {
sockprintf(socket,session, "550 Relay not allowed.");
stats.msgs_refused++;
}
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);
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 '"' */
p=alias(&scfg,p,name_alias_buf);
if(p==name_alias_buf)
lprintf(LOG_DEBUG,"%04d SMTP NAME ALIAS: %s (for %s)"
,socket,p,rcpt_addr);
/* Check if message is to be processed by an external mail processor */
for(i=0;i<mailproc_count;i++) {
if(!mailproc_list[i].process_dnsbl && dnsbl_result.s_addr)
continue;
if(!mailproc_list[i].process_spam && spam_bait_result)
continue;
if(!chk_ar(&scfg,mailproc_list[i].ar,&relay_user,&client))
continue;
if(findstr_in_list(p, mailproc_list[i].to) || findstr_in_list(rcpt_addr, mailproc_list[i].to)) {
break;
}
mailproc_match=i;
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_NOTICE,"%04d !SMTP UNKNOWN SUB-BOARD: %s", socket, p);
sockprintf(socket,session, "550 Unknown sub-board: %s", p);
continue;
}
subnum=i;
state=SMTP_STATE_RCPT_TO;
rcpt_count++;
continue;
}
/* destined for a (non-passthru) external mail processor */
if(mailproc_match<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[mailproc_match].name);
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);
state=SMTP_STATE_RCPT_TO;
continue;
}
}
if((p==alias_buf || p==name_alias_buf || startup->options&MAIL_OPT_ALLOW_RX_BY_NUMBER)
&& isdigit((uchar)*p)) {
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=smtp_matchuser(&scfg,p,startup->options&MAIL_OPT_ALLOW_SYSOP_ALIASES,FALSE);
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=smtp_matchuser(&scfg, p, FALSE, TRUE);
if(!usernum && scfg.msg_misc&MM_REALNAME) /* RX by "real.name" */
usernum=smtp_matchuser(&scfg, rcpt_name, FALSE, TRUE);
if(!usernum && startup->default_user[0]) {
usernum=matchuser(&scfg,startup->default_user,TRUE /* sysop_alias */);

rswindell
committed
lprintf(LOG_INFO,"%04d SMTP Forwarding mail for UNKNOWN USER to default user: '%s' #%u"
,socket,startup->default_user,usernum);

rswindell
committed
lprintf(LOG_WARNING,"%04d !SMTP UNKNOWN DEFAULT USER: '%s'"
,socket,startup->default_user);
}
lprintf(LOG_INFO,"%04d SMTP Blocked tag: %s", socket, rcpt_to);
sockprintf(socket,session, "550 Unknown User: %s", rcpt_to);

rswindell
committed
lprintf(LOG_WARNING,"%04d !SMTP UNKNOWN USER: '%s'", socket, rcpt_to);
sockprintf(socket,session, "550 Unknown User: %s", rcpt_to);
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,session, "550 Unknown User: %s", rcpt_to);
continue;
}
if(user.misc&(DELETED|INACTIVE)) {
lprintf(LOG_WARNING,"%04d !SMTP DELETED or INACTIVE user #%u (%s)"
sockprintf(socket,session, "550 Unknown User: %s", rcpt_to);
if(cmd==SMTP_CMD_MAIL) {
if((user.rest&FLAG('M')) && relay_user.number==0) {
lprintf(LOG_NOTICE,"%04d !SMTP M-restricted user #u (%s) cannot receive unauthenticated SMTP mail"
,socket, user.number, user.alias);
sockprintf(socket,session, "550 Closed mailbox: %s", rcpt_to);
stats.msgs_refused++;
continue;
}
if(startup->max_msgs_waiting && !(user.exempt&FLAG('W'))
&& (waiting=getmail(&scfg, user.number, /* sent: */FALSE, /* spam: */FALSE)) > startup->max_msgs_waiting) {
lprintf(LOG_NOTICE,"%04d !SMTP User #%u (%s) mailbox (%u msgs) exceeds the maximum (%u) msgs waiting"
,socket, user.number, user.alias, waiting, startup->max_msgs_waiting);
sockprintf(socket,session, "450 Mailbox full: %s", rcpt_to);
stats.msgs_refused++;
continue;
}
}
else 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,session,"450 User unavailable");

rswindell
committed
continue;
}
}

rswindell
committed
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,session,"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);
}
}
/* Message Data (header and body) */
if(!strnicmp(buf,"DATA",4)) {
lprintf(LOG_WARNING,"%04d !SMTP MISSING 'RCPT TO' command", socket);
sockprintf(socket,session, badseq_rsp);
if(msgtxt!=NULL) {
fclose(msgtxt), msgtxt=NULL;
}
remove(msgtxt_fname);
if((msgtxt=fopen(msgtxt_fname,"w+b"))==NULL) {
lprintf(LOG_ERR,"%04d !SMTP ERROR %d opening %s"
,socket, errno, msgtxt_fname);
sockprintf(socket,session, insuf_stor);

rswindell
committed
/* These vars are potentially over-written by parsing an RFC822 header */
/* get sender_addr */
p=strrchr(reverse_path,'<');

rswindell
committed
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,session, "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;
lprintf(LOG_INFO,"%04d SMTP Receiving %s message from: %s to %s"
,socket, telegram ? "telegram":"mail", reverse_path, rcpt_addr);
hdr_lines=0;
if(session == -1 && !stricmp(buf,"STARTTLS")) {
if (get_ssl_cert(&scfg, &estr, &level) == -1) {
if (estr) {
lprintf(level, "%04d !SMTP %s", socket, estr);
free_crypt_attrstr(estr);
sockprintf(socket, session, "454 TLS not available");
continue;
}
if ((cstat=cryptCreateSession(&session, CRYPT_UNUSED, CRYPT_SESSION_SSL_SERVER)) != CRYPT_OK) {
GCES(cstat, "SMTP", socket, CRYPT_UNUSED, "creating TLS session");
sockprintf(socket, session, "454 TLS not available");
continue;
}
if ((cstat=cryptSetAttribute(session, CRYPT_SESSINFO_SSL_OPTIONS, CRYPT_SSLOPTION_DISABLE_CERTVERIFY)) != CRYPT_OK) {
GCES(cstat, "SMTP", socket, session, "disabling certificate verification");
cryptDestroySession(session);
session = -1;
sockprintf(socket, session, "454 TLS not available");
continue;
}
if ((cstat=cryptSetAttribute(session, CRYPT_SESSINFO_PRIVATEKEY, scfg.tls_certificate)) != CRYPT_OK) {
GCES(cstat, "SMTP", socket, session, "setting private key");
lprintf(LOG_ERR, "%04d !SMTP Unable to set private key", socket);
cryptDestroySession(session);
session = -1;
sockprintf(socket, session, "454 TLS not available");
continue;
}
nodelay = TRUE;
setsockopt(socket,IPPROTO_TCP,TCP_NODELAY,(char*)&nodelay,sizeof(nodelay));
nb=0;
ioctlsocket(socket,FIONBIO,&nb);
if ((cstat = cryptSetAttribute(session, CRYPT_SESSINFO_NETWORKSOCKET, socket)) != CRYPT_OK) {
GCES(cstat, "SMTP", socket, session, "setting network socket");
cryptDestroySession(session);
session = -1;
sockprintf(socket, session, "454 TLS not available");
continue;
}
sockprintf(socket, -1, "220 Ready to start TLS");
if ((cstat=cryptSetAttribute(session, CRYPT_SESSINFO_ACTIVE, 1)) != CRYPT_OK) {
GCES(cstat, "SMTP", socket, session, "setting session active");
}
if (startup->max_inactivity) {
if ((cstat=cryptSetAttribute(session, CRYPT_OPTION_NET_READTIMEOUT, startup->max_inactivity)) != CRYPT_OK) {
GCES(cstat, "SMTP", socket, session, "setting read timeout");
break;
}
}
continue;
}
sockprintf(socket,session,"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)
if(!(startup->options&MAIL_OPT_DEBUG_RX_BODY))
remove(msgtxt_fname);
if(rcptlst!=NULL)
remove(rcptlst_fname);
if(spy!=NULL)
fclose(spy);
js_cleanup(js_runtime, js_cx, &js_glob);
status(STATUS_WFC);
protected_uint32_adjust(&active_clients, -1);
update_clients();
{
int32_t remain = thread_down();
lprintf(LOG_INFO,"%04d SMTP Session thread terminated (%u threads remain, %lu clients served)"
,socket, remain, ++stats.smtp_served);
}
/* Must be last */
mail_close_socket(&socket, &session);
BOOL bounce(SOCKET sock, 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,"%04d !SEND Delivery attempt #%u FAILED (%s) for message #%lu from %s to %s"
,sock
,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,"%04d !SEND BOUNCE ERROR %d (%s) incrementing delivery attempt counter of message #%lu"
,sock, i, smb->last_error, msg->hdr.number);
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,"%04d !SEND BOUNCE ERROR %d (%s) deleting message"
,sock, i, smb->last_error);
if(msg->from_agent==AGENT_SMTPSYSMSG /* don't bounce 'bounce messages' */
|| (msg->hdr.attr&MSG_NOREPLY)
|| (msg->idx.from==0 && msg->from_net.type==NET_NONE)
|| (msg->reverse_path!=NULL && *msg->reverse_path==0)) {
lprintf(LOG_WARNING,"%04d !SEND Deleted undeliverable message from %s", sock, msg->from);
return(TRUE);
}
newmsg.hfield=NULL;
newmsg.hfield_dat=NULL;
newmsg.total_hfields=0;
newmsg.hdr.delivery_attempts=0;
char* reverse_path = msg->reverse_path==NULL ? msg->from : msg->reverse_path;
lprintf(LOG_WARNING,"%04d !SEND Bouncing message back to %s", sock, reverse_path);
SAFEPRINTF(str,"Delivery failure: %s",newmsg.subj);
smb_hfield_str(&newmsg, SUBJECT, str);
smb_hfield_str(&newmsg, RECIPIENT, reverse_path);
if(msg->from_agent==AGENT_PERSON) {
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);
}
} else {
smb_hfield(&newmsg, RECIPIENTAGENT, sizeof(msg->from_agent), &msg->from_agent);
}
newmsg.hdr.attr|=MSG_NOREPLY;
newmsg.hdr.attr&=~MSG_READ;
if(scfg.sys_misc&SM_DELREADM)
newmsg.hdr.attr |= MSG_KILLREAD;
strcpy(str,"Mail Delivery Subsystem");
smb_hfield_str(&newmsg, SENDER, str);
smb_hfield(&newmsg, SENDERAGENT, sizeof(agent), &agent);
smb_hfield_str(&newmsg, RFC822MSGID, get_msgid(&scfg, INVALID_SUB, &newmsg, msgid, sizeof(msgid)));
/* Put error message in subject for now */
if(msg->hdr.delivery_attempts>1)
SAFEPRINTF(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->from
,(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:");
if((i=smb_addmsghdr(smb,&newmsg,smb_storage_mode(&scfg, smb)))!=SMB_SUCCESS)
lprintf(LOG_ERR,"%04d !BOUNCE ERROR %d (%s) adding message header"
,sock,i,smb->last_error);
else {
lprintf(LOG_WARNING,"%04d !SEND Delivery failure notification (message #%ld) created for %s"
,sock, newmsg.hdr.number, reverse_path);
if((i=smb_incmsg_dfields(smb,&newmsg,1))!=SMB_SUCCESS)
lprintf(LOG_ERR,"%04d !SEND BOUNCE ERROR %d (%s) incrementing data allocation units"
,sock, 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;
if(!isalnum(dns_server[0])) {
if((list=getNameServerList())!=NULL) {
if((count=strListCount(list))>0) {
lprintf(LOG_DEBUG,"0000 SEND using auto-detected DNS server address: %s"
,dns_server);
}
freeNameServerList(list);
}
}
}
static BOOL sendmail_open_socket(SOCKET *sock, CRYPT_SESSION *session, smb_t *smb, smbmsg_t *msg)
{
int i;
SOCKADDR_IN addr;
if (*sock != INVALID_SOCKET)
mail_close_socket(sock, session);
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
if((*sock=socket(AF_INET, SOCK_STREAM, IPPROTO_IP))==INVALID_SOCKET) {
remove_msg_intransit(smb,msg);
lprintf(LOG_ERR,"0000 !SEND ERROR %d opening socket", ERROR_VALUE);
return FALSE;
}
mail_open_socket(*sock,"smtp|sendmail");
if(startup->connect_timeout) { /* Use non-blocking socket */
long nbio=1;
if((i=ioctlsocket(*sock, FIONBIO, &nbio))!=0) {
remove_msg_intransit(smb,msg);
lprintf(LOG_ERR,"%04d !SEND ERROR %d (%d) disabling blocking on socket"
,*sock, i, ERROR_VALUE);
return FALSE;
}
}
memset(&addr,0,sizeof(addr));
addr.sin_addr.s_addr = htonl(startup->outgoing4.s_addr);
addr.sin_family = AF_INET;
i=bind(*sock,(struct sockaddr *)&addr, sizeof(addr));
if(i!=0) {
remove_msg_intransit(smb,msg);
lprintf(LOG_ERR,"%04d !SEND ERROR %d (%d) binding socket", *sock, i, ERROR_VALUE);
return FALSE;
}
return TRUE;
}
static SOCKET sendmail_negotiate(CRYPT_SESSION *session, smb_t *smb, smbmsg_t *msg, const char *mx, const char *mx2, const char *server, link_list_t *failed_server_list, ushort port)
{
int i;
int tls_retry;
SOCKET sock=INVALID_SOCKET;
list_node_t* node;
ulong ip_addr;
union xp_sockaddr server_addr;
char server_ip[INET6_ADDRSTRLEN];
BOOL success;
BOOL nodelay=TRUE;
ulong nb = 0;
int status;
char buf[512];
char err[1024];
strcpy(err,"UNKNOWN ERROR");
for (tls_retry = 0; tls_retry < 2; tls_retry++) {
if (!sendmail_open_socket(&sock, session, smb, msg))
continue;
success=FALSE;
for(i=0;i<2 && !success;i++) {
if(i) {
if(startup->options&MAIL_OPT_RELAY_TX || !mx2[0])
break;
lprintf(LOG_DEBUG,"%04d SEND reverting to second MX: %s", sock, mx2);
server=mx2; /* Give second mx record a try */