Newer
Older
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) {
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
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) {
fidoaddr_t faddr = scfg.faddr[0];
faddr.point = 0;
if((sscanf(dest_host,"p%hu.f%hu.n%hu.z%hu.fidonet"
,&faddr.point
,&faddr.node
,&faddr.net
,&faddr.zone)==4
||
sscanf(dest_host,"f%hu.n%hu.z%hu.fidonet"
,&faddr.node
,&faddr.net
,&faddr.zone)==3
) && faddr.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, NULL) == -1) {
lprintf(LOG_ERR, "%04d !SMTP Unable to get certificate", socket);
sockprintf(socket, session, "454 TLS not available");
continue;
}
if (cryptCreateSession(&session, CRYPT_UNUSED, CRYPT_SESSION_SSL_SERVER) != CRYPT_OK) {
lprintf(LOG_ERR, "%04d !SMTP Unable to create TLS session", socket);
sockprintf(socket, session, "454 TLS not available");
continue;
}
if (cryptSetAttribute(session, CRYPT_SESSINFO_SSL_OPTIONS, CRYPT_SSLOPTION_DISABLE_CERTVERIFY) != CRYPT_OK) {
lprintf(LOG_ERR, "%04d !SMTP Unable to disable certificate verification", socket);
cryptDestroySession(session);
session = -1;
sockprintf(socket, session, "454 TLS not available");
continue;
}
if (cryptSetAttribute(session, CRYPT_SESSINFO_PRIVATEKEY, scfg.tls_certificate) != CRYPT_OK) {
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 ((rd = cryptSetAttribute(session, CRYPT_SESSINFO_NETWORKSOCKET, socket)) != CRYPT_OK) {
lprintf(LOG_ERR, "%04d !SMTP Unable to set network socket", socket);
cryptDestroySession(session);
session = -1;
sockprintf(socket, session, "454 TLS not available");
continue;
}
sockprintf(socket, -1, "220 Ready to start TLS");
if (cryptSetAttribute(session, CRYPT_SESSINFO_ACTIVE, 1) != CRYPT_OK) {
lprintf(LOG_ERR, "%04d !SMTP Unable to set session active", socket);
}
if (startup->max_inactivity) {
if (cryptSetAttribute(session, CRYPT_OPTION_NET_READTIMEOUT, startup->max_inactivity) != CRYPT_OK) {
lprintf(LOG_ERR, "%04d !SMTP Unable to set max inactivity", socket);
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);
}
if (session != -1)
cryptDestroySession(session);
/* Must be last */
mail_close_socket(socket);
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"
,sock, 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,"%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);
}
}
}
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936
4937
static BOOL sendmail_open_socket(SOCKET *sock, smb_t *smb, smbmsg_t *msg)
{
int i;
SOCKADDR_IN addr;
if (*sock != INVALID_SOCKET)
mail_close_socket(*sock);
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;
}
4938
4939
4940
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
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
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;
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 *estr;
char buf[512];
char err[1024];
strcpy(err,"UNKNOWN ERROR");
for (tls_retry = 0; tls_retry < 2; tls_retry++) {
if (*session != -1) {
cryptDestroySession(*session);
*session = -1;
}
if (!sendmail_open_socket(&sock, 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 */
}
lprintf(LOG_DEBUG,"%04d SEND resolving SMTP hostname: %s", sock, server);
ip_addr=resolve_ip(server);
if(ip_addr==INADDR_NONE) {
SAFEPRINTF(err, "Error resolving hostname %s", server);
lprintf(LOG_WARNING,"%04d !SEND failure resolving hostname: %s", sock, server);
continue;
}
memset(&server_addr,0,sizeof(server_addr));
server_addr.in.sin_addr.s_addr = ip_addr;
server_addr.in.sin_family = AF_INET;
server_addr.in.sin_port = htons(port);
inet_addrtop(&server_addr,server_ip,sizeof(server_ip));
if((node=listFindNode(failed_server_list,&server_addr,sizeof(server_addr))) != NULL) {
SAFEPRINTF4(err, "Error %ld connecting to port %u on %s [%s]", node->tag, inet_addrport(&server_addr), server, server_ip);
lprintf(LOG_INFO,"%04d SEND skipping failed SMTP server: %s", sock, err);
continue;
}
if((server==mx || server==mx2)
&& ((ip_addr&0xff)==127 || ip_addr==0)) {
SAFEPRINTF2(err,"Bad IP address (%s) for MX server: %s"
,server_ip,server);
lprintf(LOG_INFO, "%04d SEND %s", err);
continue;
}