2016-11-12 10:48:08 +01:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2017-01-18 09:38:30 +01:00
# include <netdb.h>
2016-11-12 10:48:08 +01:00
# include <piler.h>
int get_session_slot ( struct smtp_session * * sessions , int max_connections ) ;
2017-08-08 15:34:45 +02:00
void init_smtp_session ( struct smtp_session * session , int slot , int sd , struct config * cfg ) ;
2016-11-12 10:48:08 +01:00
# ifdef HAVE_LIBWRAP
int is_blocked_by_tcp_wrappers ( int sd ) {
struct request_info req ;
request_init ( & req , RQ_DAEMON , " piler " , RQ_FILE , sd , 0 ) ;
fromhost ( & req ) ;
if ( ! hosts_access ( & req ) ) {
send ( sd , SMTP_RESP_550_ERR_YOU_ARE_BANNED_BY_LOCAL_POLICY , strlen ( SMTP_RESP_550_ERR_YOU_ARE_BANNED_BY_LOCAL_POLICY ) , 0 ) ;
syslog ( LOG_PRIORITY , " denied connection from %s by tcp_wrappers " , eval_client ( & req ) ) ;
return 1 ;
}
return 0 ;
}
# endif
2017-08-08 15:34:45 +02:00
int start_new_session ( struct smtp_session * * sessions , int socket , int * num_connections , struct config * cfg ) {
2016-11-12 10:48:08 +01:00
char smtp_banner [ SMALLBUFSIZE ] ;
int slot ;
/*
* We have enough connections to serve already
*/
if ( * num_connections > = cfg - > max_connections ) {
2017-08-08 15:34:45 +02:00
syslog ( LOG_PRIORITY , " ERROR: too many connections (%d), cannot accept socket %d " , * num_connections , socket ) ;
2016-11-12 10:48:08 +01:00
send ( socket , SMTP_RESP_421_ERR_ALL_PORTS_ARE_BUSY , strlen ( SMTP_RESP_421_ERR_ALL_PORTS_ARE_BUSY ) , 0 ) ;
close ( socket ) ;
return - 1 ;
}
# ifdef HAVE_LIBWRAP
if ( is_blocked_by_tcp_wrappers ( socket ) = = 1 ) {
close ( socket ) ;
return - 1 ;
}
# endif
slot = get_session_slot ( sessions , cfg - > max_connections ) ;
if ( slot > = 0 & & sessions [ slot ] = = NULL ) {
sessions [ slot ] = malloc ( sizeof ( struct smtp_session ) ) ;
if ( sessions [ slot ] ) {
init_smtp_session ( sessions [ slot ] , slot , socket , cfg ) ;
snprintf ( smtp_banner , sizeof ( smtp_banner ) - 1 , SMTP_RESP_220_BANNER , cfg - > hostid ) ;
send ( socket , smtp_banner , strlen ( smtp_banner ) , 0 ) ;
( * num_connections ) + + ;
return 0 ;
}
else {
syslog ( LOG_PRIORITY , " ERROR: malloc() in start_new_session() " ) ;
}
}
else {
syslog ( LOG_PRIORITY , " ERROR: couldn't find a slot for the connection " ) ;
}
send ( socket , SMTP_RESP_421_ERR_TMP , strlen ( SMTP_RESP_421_ERR_TMP ) , 0 ) ;
close ( socket ) ;
return - 1 ;
}
int get_session_slot ( struct smtp_session * * sessions , int max_connections ) {
int i ;
for ( i = 0 ; i < max_connections ; i + + ) {
if ( sessions [ i ] = = NULL ) return i ;
}
return - 1 ;
}
struct smtp_session * get_session_by_socket ( struct smtp_session * * sessions , int max_connections , int socket ) {
int i ;
for ( i = 0 ; i < max_connections ; i + + ) {
2017-08-08 15:34:45 +02:00
if ( sessions [ i ] & & sessions [ i ] - > net . socket = = socket ) return sessions [ i ] ;
2016-11-12 10:48:08 +01:00
}
return NULL ;
}
2017-08-08 15:34:45 +02:00
void init_smtp_session ( struct smtp_session * session , int slot , int sd , struct config * cfg ) {
2017-01-18 09:38:30 +01:00
struct sockaddr_in addr ;
socklen_t addr_size = sizeof ( struct sockaddr_in ) ;
char hbuf [ NI_MAXHOST ] , sbuf [ NI_MAXSERV ] ;
2018-02-20 15:59:21 +01:00
int i ;
2017-01-18 09:38:30 +01:00
2016-11-12 10:48:08 +01:00
session - > slot = slot ;
session - > buflen = 0 ;
session - > protocol_state = SMTP_STATE_INIT ;
session - > cfg = cfg ;
2017-08-08 15:34:45 +02:00
session - > net . socket = sd ;
session - > net . use_ssl = 0 ; // use SSL/TLS
session - > net . starttls = 0 ; // SSL/TLS communication is active (1) or not (0)
session - > net . ctx = NULL ;
session - > net . ssl = NULL ;
2016-11-12 10:48:08 +01:00
2017-08-30 20:46:39 +02:00
session - > fd = - 1 ;
2018-02-20 15:59:21 +01:00
memset ( session - > mailfrom , 0 , SMALLBUFSIZE ) ;
session - > num_of_rcpt_to = 0 ;
for ( i = 0 ; i < MAX_RCPT_TO ; i + + ) memset ( session - > rcptto [ i ] , 0 , SMALLBUFSIZE ) ;
2016-11-12 10:48:08 +01:00
memset ( session - > buf , 0 , SMALLBUFSIZE ) ;
memset ( session - > remote_host , 0 , INET6_ADDRSTRLEN ) ;
reset_bdat_counters ( session ) ;
time ( & ( session - > lasttime ) ) ;
2017-01-18 09:38:30 +01:00
2017-08-08 15:34:45 +02:00
if ( getpeername ( session - > net . socket , ( struct sockaddr * ) & addr , & addr_size ) = = 0 & &
2017-01-18 09:38:30 +01:00
getnameinfo ( ( struct sockaddr * ) & addr , addr_size , hbuf , sizeof ( hbuf ) , sbuf , sizeof ( sbuf ) , NI_NUMERICHOST | NI_NUMERICSERV ) = = 0 ) {
snprintf ( session - > remote_host , INET6_ADDRSTRLEN - 1 , " %s " , hbuf ) ;
}
2016-11-12 10:48:08 +01:00
}
void free_smtp_session ( struct smtp_session * session ) {
if ( session ) {
2017-08-08 15:34:45 +02:00
if ( session - > net . use_ssl = = 1 ) {
SSL_shutdown ( session - > net . ssl ) ;
SSL_free ( session - > net . ssl ) ;
2016-11-12 10:48:08 +01:00
}
2017-08-08 15:34:45 +02:00
if ( session - > net . ctx ) SSL_CTX_free ( session - > net . ctx ) ;
2016-11-12 10:48:08 +01:00
free ( session ) ;
}
}
void tear_down_session ( struct smtp_session * * sessions , int slot , int * num_connections ) {
2017-11-04 15:34:34 +01:00
syslog ( LOG_PRIORITY , " disconnected from %s on descriptor %d (%d active connections) " , sessions [ slot ] - > remote_host , sessions [ slot ] - > net . socket , ( * num_connections ) - 1 ) ;
2016-11-12 10:48:08 +01:00
2017-08-08 15:34:45 +02:00
close ( sessions [ slot ] - > net . socket ) ;
2016-11-12 10:48:08 +01:00
free_smtp_session ( sessions [ slot ] ) ;
sessions [ slot ] = NULL ;
( * num_connections ) - - ;
}
2018-02-20 15:59:21 +01:00
void handle_data ( struct smtp_session * session , char * readbuf , int readlen , struct config * cfg ) {
2016-11-12 10:48:08 +01:00
char * p , puf [ MAXBUFSIZE ] ;
int result ;
// process BDAT stuff
if ( session - > protocol_state = = SMTP_STATE_BDAT ) {
if ( session - > bad = = 1 ) {
// something bad happened in the BDAT processing
return ;
}
2018-02-20 15:59:21 +01:00
process_bdat ( session , readbuf , readlen , cfg ) ;
2016-11-12 10:48:08 +01:00
}
// process DATA
else if ( session - > protocol_state = = SMTP_STATE_DATA ) {
process_data ( session , readbuf , readlen ) ;
}
// process other SMTP commands
else {
if ( session - > buflen > 0 ) {
snprintf ( puf , sizeof ( puf ) - 1 , " %s%s " , session - > buf , readbuf ) ;
snprintf ( readbuf , BIGBUFSIZE - 1 , " %s " , puf ) ;
session - > buflen = 0 ;
memset ( session - > buf , 0 , SMALLBUFSIZE ) ;
}
p = readbuf ;
do {
memset ( puf , 0 , sizeof ( puf ) ) ;
p = split ( p , ' \n ' , puf , sizeof ( puf ) - 1 , & result ) ;
if ( puf [ 0 ] = = ' \0 ' ) continue ;
if ( result = = 1 ) {
2018-02-20 15:59:21 +01:00
process_smtp_command ( session , puf , cfg ) ;
2016-11-12 10:48:08 +01:00
// if chunking is enabled and we have data after BDAT <len>
// then process the rest
if ( session - > cfg - > enable_chunking = = 1 & & p & & session - > protocol_state = = SMTP_STATE_BDAT ) {
2018-02-20 15:59:21 +01:00
process_bdat ( session , p , strlen ( p ) , cfg ) ;
2016-11-12 10:48:08 +01:00
break ;
}
}
else {
snprintf ( session - > buf , SMALLBUFSIZE - 1 , " %s " , puf ) ;
session - > buflen = strlen ( puf ) ;
}
} while ( p ) ;
}
}
2018-02-20 15:59:21 +01:00
void write_envelope_addresses ( struct smtp_session * session ) {
int i ;
char s [ SMALLBUFSIZE ] ;
if ( session - > fd = = - 1 ) return ;
snprintf ( s , sizeof ( s ) - 1 , " X-Piler-Envelope-From: %s \n " , session - > mailfrom ) ;
if ( write ( session - > fd , s , strlen ( s ) ) = = - 1 ) syslog ( LOG_PRIORITY , " ERROR: %s: cannot write envelope from address " , session - > ttmpfile ) ;
for ( i = 0 ; i < session - > num_of_rcpt_to ; i + + ) {
if ( i = = 0 ) snprintf ( s , sizeof ( s ) - 1 , " X-Piler-Envelope-To: %s \n " , session - > rcptto [ session - > num_of_rcpt_to ] ) ;
else snprintf ( s , sizeof ( s ) - 1 , " %s \n " , session - > rcptto [ session - > num_of_rcpt_to ] ) ;
if ( write ( session - > fd , s , strlen ( s ) ) = = - 1 ) syslog ( LOG_PRIORITY , " ERROR: %s: cannot write envelope to address " , session - > ttmpfile ) ;
}
}