Newer
Older
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;
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)
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->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;
size_t len;
BOOL sending_locally=FALSE;
SetThreadName("SendMail");
thread_up(TRUE /* setuid */);
sendmail_running=TRUE;
terminate_sendmail=FALSE;
lprintf(LOG_INFO,"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);
SAFEPRINTF(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_NOTICE,"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);
remove_ctrl_a(msgtxt, msgtxt);
port=0;
mx2[0]=0;
/* 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, /* immediate: */TRUE);
continue;
}
p++;
SAFEPRINTF(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 {
SAFEPRINTF4(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, INADDR_ANY, 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,dns_server);
SAFEPRINTF2(err,"Error %d obtaining MX record for %s",i,p);
bounce(&smb,&msg,err, /* immediate: */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;
i=bind(sock,(struct sockaddr *)&addr, sizeof(addr));
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;
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,"Failed to resolve SMTP hostname: %s",server);
lprintf(LOG_WARNING,"%04d !SEND failure resolving hostname: %s", sock, 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,/* immediate: */FALSE);
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,/* immediate: */buf[0]=='5');
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,/* immediate: */buf[0]=='5');
/* AUTH */
if(startup->options&MAIL_OPT_RELAY_TX
&& (startup->options&MAIL_OPT_RELAY_AUTH_MASK)!=0 && !sending_locally) {
if((startup->options&MAIL_OPT_RELAY_AUTH_MASK)==MAIL_OPT_RELAY_AUTH_PLAIN) {
/* Build the buffer: <username>\0<user-id>\0<password */
len=safe_snprintf(buf,sizeof(buf),"%s%c%s%c%s"
,startup->relay_user
,0
,startup->relay_user
,0
,startup->relay_pass);
b64_encode(resp,sizeof(resp),buf,len);
sockprintf(sock,"AUTH PLAIN %s",resp);
} else {
switch(startup->options&MAIL_OPT_RELAY_AUTH_MASK) {
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,/* immediate: */buf[0]=='5');
continue;
}
switch(startup->options&MAIL_OPT_RELAY_AUTH_MASK) {
case MAIL_OPT_RELAY_AUTH_LOGIN:
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
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,/* immediate: */buf[0]=='5');
continue;
}
switch(startup->options&MAIL_OPT_RELAY_AUTH_MASK) {
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,/* immediate: */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,/* immediate: */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,/* immediate: */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,/* immediate: */buf[0]=='5');
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,/* immediate: */buf[0]=='5');
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);
if(msg.from_agent==AGENT_PERSON && !(startup->options&MAIL_OPT_NO_AUTO_EXEMPT))
exempt_email_addr("SEND Auto-exempting",msg.from,fromaddr,toaddr);
/* 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_INFO,"%04d Mail Server terminate",server_socket);
terminate_server=TRUE;
}
static void cleanup(int code)
{
int i;
semfile_list_free(&recycle_semfiles);
semfile_list_free(&shutdown_semfiles);
if(mailproc_list!=NULL) {
for(i=0;i<mailproc_count;i++) {
if(mailproc_list[i].ar!=NULL && mailproc_list[i].ar!=nular)
free(mailproc_list[i].ar);
strListFree(&mailproc_list[i].to);
strListFree(&mailproc_list[i].from);
}
FREE_AND_NULL(mailproc_list);
}
if(server_socket!=INVALID_SOCKET) {

rswindell
committed
mail_close_socket(server_socket);
server_socket=INVALID_SOCKET;
}
if(submission_socket!=INVALID_SOCKET) {
mail_close_socket(submission_socket);
submission_socket=INVALID_SOCKET;
}
if(pop3_socket!=INVALID_SOCKET) {

rswindell
committed
mail_close_socket(pop3_socket);
pop3_socket=INVALID_SOCKET;
}
update_clients();
#ifdef _WINSOCKAPI_
if(WSAInitialized && WSACleanup()!=0)
lprintf(LOG_ERR,"0000 !WSACleanup ERROR %d",ERROR_VALUE);
thread_down();
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
if(terminate_server || code) {
char str[1024];
sprintf(str,"%u connections served", stats.connections_served);
if(stats.connections_refused)
sprintf(str+strlen(str),", %u refused", stats.connections_refused);
if(stats.connections_ignored)
sprintf(str+strlen(str),", %u ignored", stats.connections_refused);
if(stats.sessions_refused)
sprintf(str+strlen(str),", %u sessions refused", stats.sessions_refused);
sprintf(str+strlen(str),", %u messages received", stats.msgs_received);
if(stats.msgs_refused)
sprintf(str+strlen(str),", %u refused", stats.msgs_refused);
if(stats.msgs_ignored)
sprintf(str+strlen(str),", %u ignored", stats.msgs_ignored);
if(stats.errors)
sprintf(str+strlen(str),", %u errors", stats.errors);
if(stats.crit_errors)
sprintf(str+strlen(str),", %u critcal", stats.crit_errors);
lprintf(LOG_INFO,"#### Mail Server thread terminated (%s)",str);
}
if(thread_count)
lprintf(LOG_WARNING,"#### !Mail Server threads (%u) remain after termination", thread_count);
if(startup!=NULL && startup->terminated!=NULL)
startup->terminated(startup->cbdata,code);
const char* DLLCALL mail_ver(void)
{
static char ver[256];
char compiler[32];
sscanf("$Revision$", "%*s %s", revision);
sprintf(ver,"%s %s%s SMBLIB %s "
,server_name
#ifdef _DEBUG
," Debug"
#else
,""
#endif
,smb_lib_ver()
,__DATE__, __TIME__, compiler
);
return(ver);
}
void DLLCALL mail_server(void* arg)
char* p;
char path[MAX_PATH+1];
char mailproc_ini[MAX_PATH+1];
char str[256];
char error[256];
char compiler[32];
SOCKADDR_IN server_addr;
SOCKADDR_IN client_addr;
socklen_t client_addr_len;
SOCKET client_socket;
int i;
int result;
ulong l;
time_t t;
time_t start;
time_t initialized=0;
SOCKET high_socket_set;
pop3_t* pop3;
smtp_t* smtp;

rswindell
committed
struct timeval tv;
FILE* fp;
str_list_t sec_list;
startup=(mail_startup_t*)arg;
#ifdef _THREAD_SUID_BROKEN
if(thread_suid_broken)
startup->seteuid(TRUE);
#endif
sbbs_beep(100,500);
fprintf(stderr, "No startup structure passed!\n");
return;
}
if(startup->size!=sizeof(mail_startup_t)) { /* verify size */
sbbs_beep(100,500);
sbbs_beep(300,500);
sbbs_beep(100,500);
fprintf(stderr, "Invalid startup structure!\n");
return;
}
/* Setup intelligent defaults */
if(startup->relay_port==0) startup->relay_port=IPPORT_SMTP;
if(startup->submission_port==0) startup->submission_port=IPPORT_SUBMISSION;
if(startup->smtp_port==0) startup->smtp_port=IPPORT_SMTP;
if(startup->pop3_port==0) startup->pop3_port=IPPORT_POP3;
if(startup->rescan_frequency==0) startup->rescan_frequency=3600; /* 60 minutes */
if(startup->max_delivery_attempts==0) startup->max_delivery_attempts=50;
if(startup->max_inactivity==0) startup->max_inactivity=120; /* seconds */
if(startup->max_recipients==0) startup->max_recipients=100;
if(startup->sem_chk_freq==0) startup->sem_chk_freq=2;

rswindell
committed
#ifdef JAVASCRIPT
if(startup->js.max_bytes==0) startup->js.max_bytes=JAVASCRIPT_MAX_BYTES;
if(startup->js.cx_stack==0) startup->js.cx_stack=JAVASCRIPT_CONTEXT_STACK;
#endif
ZERO_VAR(js_server_props);
SAFEPRINTF2(js_server_props.version,"%s %s",server_name,revision);
js_server_props.version_detail=mail_ver();
js_server_props.clients=&active_clients;
js_server_props.options=&startup->options;
js_server_props.interface_addr=&startup->interface_addr;
uptime=0;
memset(&stats,0,sizeof(stats));
startup->recycle_now=FALSE;
startup->shutdown_now=FALSE;
terminate_server=FALSE;
SetThreadName("Mail Server");
do {
thread_up(FALSE /* setuid */);
status("Initializing");
memset(&scfg, 0, sizeof(scfg));
lprintf(LOG_INFO,"%s Revision %s%s"
,server_name
," Debug"
lprintf(LOG_INFO,"Compiled %s %s with %s", __DATE__, __TIME__, compiler);
lprintf(LOG_DEBUG,"SMBLIB %s (format %x.%02x)",smb_lib_ver(),smb_ver()>>8,smb_ver()&0xff);
sbbs_srand();
if(!winsock_startup()) {

rswindell
committed
cleanup(1);
return;
}
t=time(NULL);
lprintf(LOG_INFO,"Initializing on %.24s with options: %lx"
,ctime_r(&t,str),startup->options);
if(chdir(startup->ctrl_dir)!=0)
lprintf(LOG_ERR,"!ERROR %d changing directory to: %s", errno, startup->ctrl_dir);
/* Initial configuration and load from CNF files */
SAFECOPY(scfg.ctrl_dir,startup->ctrl_dir);
lprintf(LOG_INFO,"Loading configuration files from %s", scfg.ctrl_dir);
scfg.size=sizeof(scfg);
SAFECOPY(error,UNKNOWN_LOAD_ERROR);
if(!load_cfg(&scfg, NULL, TRUE, error)) {
lprintf(LOG_CRIT,"!ERROR %s",error);
lprintf(LOG_CRIT,"!Failed to load configuration files");
cleanup(1);
return;
}
if(startup->temp_dir[0])
SAFECOPY(scfg.temp_dir,startup->temp_dir);
else
SAFECOPY(scfg.temp_dir,"../temp");
prep_dir(scfg.ctrl_dir, scfg.temp_dir, sizeof(scfg.temp_dir));
MKDIR(scfg.temp_dir);
lprintf(LOG_DEBUG,"Temporary file directory: %s", scfg.temp_dir);
if(!isdir(scfg.temp_dir)) {
lprintf(LOG_CRIT,"!Invalid temp directory: %s", scfg.temp_dir);
/* Parse the mailproc[.host].ini */
mailproc_list=NULL;
mailproc_count=0;
iniFileName(mailproc_ini,sizeof(mailproc_ini),scfg.ctrl_dir,"mailproc.ini");
if((fp=iniOpenFile(mailproc_ini, /* create? */FALSE))!=NULL) {
lprintf(LOG_DEBUG,"Reading %s",mailproc_ini);
sec_list = iniReadSectionList(fp,/* prefix */NULL);
if((mailproc_count=strListCount(sec_list))!=0
&& (mailproc_list=malloc(mailproc_count*sizeof(struct mailproc)))!=NULL) {
char buf[INI_MAX_VALUE_LEN+1];
for(i=0;i<mailproc_count;i++) {
memset(&mailproc_list[i],0,sizeof(struct mailproc));
SAFECOPY(mailproc_list[i].name,sec_list[i]);
SAFECOPY(mailproc_list[i].cmdline,
iniReadString(fp,sec_list[i],"Command",sec_list[i],buf));
SAFECOPY(mailproc_list[i].eval,
iniReadString(fp,sec_list[i],"Eval","",buf));
mailproc_list[i].to =
mailproc_list[i].from =
mailproc_list[i].passthru =
mailproc_list[i].native =
mailproc_list[i].disabled =
mailproc_list[i].ignore_on_error =
iniReadBool(fp,sec_list[i],"IgnoreOnError",FALSE);
mailproc_list[i].process_spam =
iniReadBool(fp,sec_list[i],"ProcessSPAM",TRUE);
mailproc_list[i].process_dnsbl =
iniReadBool(fp,sec_list[i],"ProcessDNSBL",TRUE);
mailproc_list[i].ar =
arstr(NULL,iniReadString(fp,sec_list[i],"AccessRequirements","",buf),&scfg);
}
}
iniFreeStringList(sec_list);
iniCloseFile(fp);
}
if(startup->host_name[0]==0)
SAFECOPY(startup->host_name,scfg.sys_inetaddr);
if((t=checktime())!=0) { /* Check binary time */
lprintf(LOG_ERR,"!TIME PROBLEM (%ld)",t);
}
if(uptime==0)
uptime=time(NULL); /* this must be done *after* setting the timezone */
if(startup->max_clients==0) {
startup->max_clients=scfg.sys_nodes;
if(startup->max_clients<10)
startup->max_clients=10;
}
lprintf(LOG_DEBUG,"Maximum clients: %u",startup->max_clients);
lprintf(LOG_DEBUG,"Maximum inactivity: %u seconds",startup->max_inactivity);
active_clients=0,update_clients();
/* open a socket and wait for a client */
server_socket = mail_open_socket(SOCK_STREAM,"smtp");
if(server_socket == INVALID_SOCKET) {
lprintf(LOG_CRIT,"!ERROR %d opening socket", ERROR_VALUE);
cleanup(1);
return;
}
lprintf(LOG_DEBUG,"%04d SMTP socket opened",server_socket);
/*****************************/
/* Listen for incoming calls */
/*****************************/
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_addr.s_addr = htonl(startup->interface_addr);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(startup->smtp_port);
if(startup->smtp_port < IPPORT_RESERVED) {
if(startup->seteuid!=NULL)
startup->seteuid(FALSE);
}
result = retry_bind(server_socket,(struct sockaddr *)&server_addr,sizeof(server_addr)
,startup->bind_retry_count,startup->bind_retry_delay,"SMTP Server",lprintf);
if(startup->smtp_port < IPPORT_RESERVED) {
if(startup->seteuid!=NULL)
startup->seteuid(TRUE);
}
lprintf(LOG_CRIT,"%04d %s",server_socket, BIND_FAILURE_HELP);
cleanup(1);
return;
}
result = listen(server_socket, 1);
lprintf(LOG_CRIT,"%04d !ERROR %d (%d) listening on SMTP socket"
,server_socket, result, ERROR_VALUE);
cleanup(1);
return;
}
lprintf(LOG_INFO,"%04d SMTP Server listening on port %u"
,server_socket, startup->smtp_port);
if(startup->options&MAIL_OPT_USE_SUBMISSION_PORT) {
submission_socket = mail_open_socket(SOCK_STREAM,"submission");
if(submission_socket == INVALID_SOCKET) {
lprintf(LOG_CRIT,"!ERROR %d opening socket", ERROR_VALUE);
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
cleanup(1);
return;
}
lprintf(LOG_DEBUG,"%04d SUBMISSION socket opened",submission_socket);
/*****************************/
/* Listen for incoming calls */
/*****************************/
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_addr.s_addr = htonl(startup->interface_addr);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(startup->submission_port);
if(startup->submission_port < IPPORT_RESERVED) {
if(startup->seteuid!=NULL)
startup->seteuid(FALSE);
}
result = retry_bind(submission_socket,(struct sockaddr *)&server_addr,sizeof(server_addr)
,startup->bind_retry_count,startup->bind_retry_delay,"SMTP Submission Agent",lprintf);
if(startup->submission_port < IPPORT_RESERVED) {
if(startup->seteuid!=NULL)
startup->seteuid(TRUE);
}
if(result != 0) {
lprintf(LOG_CRIT,"%04d %s",submission_socket, BIND_FAILURE_HELP);