Newer
Older
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);
protected_int32_init(&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);
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
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);
cleanup(1);
return;
}
result = listen(submission_socket, 1);
if(result != 0) {
lprintf(LOG_CRIT,"%04d !ERROR %d (%d) listening on SUBMISSION socket"
,submission_socket, result, ERROR_VALUE);
cleanup(1);
return;
}
lprintf(LOG_INFO,"%04d SUBMISSION Server listening on port %u"
,submission_socket, startup->submission_port);
}
if(startup->options&MAIL_OPT_ALLOW_POP3) {
/* open a socket and wait for a client */
pop3_socket = mail_open_socket(SOCK_STREAM,"pop3");
lprintf(LOG_CRIT,"!ERROR %d opening POP3 socket", ERROR_VALUE);
cleanup(1);
return;
}
lprintf(LOG_DEBUG,"%04d POP3 socket opened",pop3_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->pop3_port);
if(startup->pop3_port < IPPORT_RESERVED) {
if(startup->seteuid!=NULL)
startup->seteuid(FALSE);
}
result = retry_bind(pop3_socket,(struct sockaddr *)&server_addr,sizeof(server_addr)
,startup->bind_retry_count,startup->bind_retry_delay,"POP3 Server",lprintf);
if(startup->pop3_port < IPPORT_RESERVED) {
if(startup->seteuid!=NULL)
startup->seteuid(FALSE);
}
lprintf(LOG_CRIT,"%04d %s",pop3_socket,BIND_FAILURE_HELP);
cleanup(1);
return;
}
result = listen(pop3_socket, 1);
lprintf(LOG_CRIT,"%04d !ERROR %d (%d) listening on POP3 socket"
,pop3_socket, result, ERROR_VALUE);
cleanup(1);
return;
lprintf(LOG_INFO,"%04d POP3 Server listening on port %u"
,pop3_socket, startup->pop3_port);
sem_init(&sendmail_wakeup_sem,0,0);
if(!(startup->options&MAIL_OPT_NO_SENDMAIL))
_beginthread(sendmail_thread, 0, NULL);
status(STATUS_WFC);
/* Setup recycle/shutdown semaphore file lists */
shutdown_semfiles=semfile_list_init(scfg.ctrl_dir,"shutdown","mail");
recycle_semfiles=semfile_list_init(scfg.ctrl_dir,"recycle","mail");
SAFEPRINTF(path,"%smailsrvr.rec",scfg.ctrl_dir); /* legacy */
semfile_list_add(&recycle_semfiles,path);
semfile_list_add(&recycle_semfiles,mailproc_ini);
if(!initialized) {
semfile_list_check(&initialized,recycle_semfiles);
semfile_list_check(&initialized,shutdown_semfiles);
/* signal caller that we've started up successfully */
if(startup->started!=NULL)
startup->started(startup->cbdata);
lprintf(LOG_INFO,"%04d Mail Server thread started",server_socket);
while(server_socket!=INVALID_SOCKET && !terminate_server) {
if(active_clients.value==0) {
if(!(startup->options&MAIL_OPT_NO_RECYCLE)) {
if((p=semfile_list_check(&initialized,recycle_semfiles))!=NULL) {
lprintf(LOG_INFO,"%04d Recycle semaphore file (%s) detected"
,server_socket,p);
break;
}
if(startup->recycle_now==TRUE) {
lprintf(LOG_NOTICE,"%04d Recycle semaphore signaled", server_socket);
startup->recycle_now=FALSE;
break;
}
if(((p=semfile_list_check(&initialized,shutdown_semfiles))!=NULL
&& lprintf(LOG_INFO,"%04d Shutdown semaphore file (%s) detected"
,server_socket,p))
|| (startup->shutdown_now==TRUE
&& lprintf(LOG_INFO,"%04d Shutdown semaphore signaled",server_socket))) {
startup->shutdown_now=FALSE;
terminate_server=TRUE;
break;
}
/* now wait for connection */
FD_ZERO(&socket_set);
FD_SET(server_socket,&socket_set);
high_socket_set=server_socket+1;
if(startup->options&MAIL_OPT_ALLOW_POP3
&& pop3_socket!=INVALID_SOCKET) {
FD_SET(pop3_socket,&socket_set);
if(pop3_socket+1>high_socket_set)
high_socket_set=pop3_socket+1;
if(startup->options&MAIL_OPT_USE_SUBMISSION_PORT
&& submission_socket!=INVALID_SOCKET) {
FD_SET(submission_socket,&socket_set);
if(submission_socket+1>high_socket_set)
high_socket_set=submission_socket+1;
}
tv.tv_sec=startup->sem_chk_freq;
tv.tv_usec=0;
if((i=select(high_socket_set,&socket_set,NULL,NULL,&tv))<1) {
continue;
if(ERROR_VALUE==EINTR)
lprintf(LOG_DEBUG,"%04d Mail Server listening interrupted",server_socket);
else if(ERROR_VALUE == ENOTSOCK)
lprintf(LOG_NOTICE,"%04d Mail Server sockets closed",server_socket);
lprintf(LOG_WARNING,"%04d !ERROR %d selecting sockets",server_socket,ERROR_VALUE);
continue;
if(server_socket!=INVALID_SOCKET && !terminate_server
&& (FD_ISSET(server_socket,&socket_set)
|| (startup->options&MAIL_OPT_USE_SUBMISSION_PORT
&& FD_ISSET(submission_socket,&socket_set)))) {
client_addr_len = sizeof(client_addr);
client_socket = accept(
FD_ISSET(server_socket,&socket_set) ? server_socket:submission_socket
,(struct sockaddr *)&client_addr
,&client_addr_len);
#if 0 /* is this necessary still? */
if(ERROR_VALUE == ENOTSOCK || ERROR_VALUE == EINVAL) {
lprintf(LOG_NOTICE,"%04d SMTP socket closed while listening"
,server_socket);
break;
}
#endif
lprintf(LOG_WARNING,"%04d SMTP !ERROR %d accepting connection"
,FD_ISSET(server_socket,&socket_set) ? server_socket:submission_socket
,ERROR_VALUE);
#ifdef _WIN32
if(WSAGetLastError()==WSAENOBUFS) /* recycle (re-init WinSock) on this error */
break;
#endif
continue;
}
if(startup->socket_open!=NULL)
startup->socket_open(startup->cbdata,TRUE);
stats.sockets++;
if(trashcan(&scfg,inet_ntoa(client_addr.sin_addr),"ip-silent")) {
mail_close_socket(client_socket);
stats.connections_ignored++;
continue;
}
if(active_clients.value>=startup->max_clients) {
lprintf(LOG_WARNING,"%04d SMTP !MAXIMUM CLIENTS (%u) reached, access denied (%u total)"
,client_socket, startup->max_clients, ++stats.connections_refused);
sockprintf(client_socket,"421 Maximum active clients reached, please try again later.");
mswait(3000);
mail_close_socket(client_socket);
continue;
}
if((i=ioctlsocket(client_socket, FIONBIO, &l))!=0) {
lprintf(LOG_CRIT,"%04d SMTP !ERROR %d (%d) disabling blocking on socket"
,client_socket, i, ERROR_VALUE);
mail_close_socket(client_socket);
continue;
}
if((smtp=malloc(sizeof(smtp_t)))==NULL) {
lprintf(LOG_CRIT,"%04d SMTP !ERROR allocating %u bytes of memory for smtp_t"
,client_socket, sizeof(smtp_t));
mail_close_socket(client_socket);
continue;
}
smtp->socket=client_socket;
smtp->client_addr=client_addr;
_beginthread(smtp_thread, 0, smtp);
stats.connections_served++;
if(pop3_socket!=INVALID_SOCKET
&& FD_ISSET(pop3_socket,&socket_set)) {
client_addr_len = sizeof(client_addr);
client_socket = accept(pop3_socket, (struct sockaddr *)&client_addr
,&client_addr_len);
#if 0 /* is this necessary still? */
if(ERROR_VALUE == ENOTSOCK || ERROR_VALUE == EINVAL) {
lprintf(LOG_NOTICE,"%04d POP3 socket closed while listening",pop3_socket);
break;
}
#endif
lprintf(LOG_WARNING,"%04d POP3 !ERROR %d accepting connection"
,pop3_socket, ERROR_VALUE);
#ifdef _WIN32
if(WSAGetLastError()==WSAENOBUFS) /* recycle (re-init WinSock) on this error */
break;
#endif
continue;
}
if(startup->socket_open!=NULL)
startup->socket_open(startup->cbdata,TRUE);
stats.sockets++;
if(trashcan(&scfg,inet_ntoa(client_addr.sin_addr),"ip-silent")) {
mail_close_socket(client_socket);
stats.connections_ignored++;
continue;
}
if(active_clients.value>=startup->max_clients) {
lprintf(LOG_WARNING,"%04d POP3 !MAXIMUM CLIENTS (%u) reached, access denied (%u total)"
,client_socket, startup->max_clients, ++stats.connections_refused);
sockprintf(client_socket,"-ERR Maximum active clients reached, please try again later.");
mswait(3000);
mail_close_socket(client_socket);
continue;
}
l=1;
if((i=ioctlsocket(client_socket, FIONBIO, &l))!=0) {
lprintf(LOG_CRIT,"%04d POP3 !ERROR %d (%d) disabling blocking on socket"
,client_socket, i, ERROR_VALUE);
sockprintf(client_socket,"-ERR System error, please try again later.");
mswait(3000);
mail_close_socket(client_socket);
continue;
}
if((pop3=malloc(sizeof(pop3_t)))==NULL) {
lprintf(LOG_CRIT,"%04d POP3 !ERROR allocating %u bytes of memory for pop3_t"
,client_socket,sizeof(pop3_t));
sockprintf(client_socket,"-ERR System error, please try again later.");
mswait(3000);
mail_close_socket(client_socket);
continue;
}
pop3->socket=client_socket;
pop3->client_addr=client_addr;
_beginthread(pop3_thread, 0, pop3);
stats.connections_served++;
if(active_clients.value) {
lprintf(LOG_DEBUG,"%04d Waiting for %d active clients to disconnect..."
,server_socket, active_clients.value);
start=time(NULL);
while(active_clients.value) {
if(time(NULL)-start>startup->max_inactivity) {
lprintf(LOG_WARNING,"%04d !TIMEOUT waiting for %d active clients"
,server_socket, active_clients.value);
break;
}
mswait(100);
if(sendmail_running) {
terminate_sendmail=TRUE;
sem_post(&sendmail_wakeup_sem);
mswait(100);
}
if(sendmail_running) {
lprintf(LOG_DEBUG,"%04d Waiting for SendMail thread to terminate..."
,server_socket);
start=time(NULL);
while(sendmail_running) {
if(time(NULL)-start>TIMEOUT_THREAD_WAIT) {
lprintf(LOG_WARNING,"%04d !TIMEOUT waiting for sendmail thread to terminate"
,server_socket);
break;
}
mswait(500);
if(!sendmail_running) {
while(sem_destroy(&sendmail_wakeup_sem)==-1 && errno==EBUSY) {
mswait(1);
cleanup(0);
if(!terminate_server) {
lprintf(LOG_INFO,"Recycling server...");
if(startup->recycle!=NULL)
startup->recycle(startup->cbdata);
} while(!terminate_server);