diff --git a/src/sbbs3/mailsrvr.c b/src/sbbs3/mailsrvr.c index db5f026b1408e19911b7a6d997d68eb140b380cb..6e9abcfcbad63aa66629fed0f40685a8f354cdc6 100644 --- a/src/sbbs3/mailsrvr.c +++ b/src/sbbs3/mailsrvr.c @@ -143,6 +143,7 @@ typedef struct { union xp_sockaddr client_addr; socklen_t client_addr_len; BOOL tls_port; + CRYPT_SESSION session; } smtp_t,pop3_t; #define GCES(status, server, sock, sess, action) do { \ @@ -150,8 +151,10 @@ typedef struct { int GCES_level; \ get_crypt_error_string(status, sess, &GCES_estr, action, &GCES_level); \ if (GCES_estr) { \ - if(GCES_level < startup->tls_error_level) \ + if (GCES_level < startup->tls_error_level) \ GCES_level = startup->tls_error_level; \ + if (GCES_level > LOG_INFO) \ + GCES_level = LOG_INFO; \ lprintf(GCES_level, "%04d %s %s", sock, server, GCES_estr); \ free_crypt_attrstr(GCES_estr); \ } \ @@ -162,8 +165,10 @@ typedef struct { int GCES_level; \ get_crypt_error_string(status, sess, &GCES_estr, action, &GCES_level); \ if (GCES_estr) { \ - if(GCES_level < startup->tls_error_level) \ - GCES_level = startup->tls_error_level; \ + if (GCES_level < startup->tls_error_level) \ + GCES_level = startup->tls_error_level; \ + if (GCES_level > LOG_INFO) \ + GCES_level = LOG_INFO; \ lprintf(GCES_level, "%04d %s [%s] %s", sock, server, host, GCES_estr); \ free_crypt_attrstr(GCES_estr); \ } \ @@ -989,7 +994,7 @@ static void badlogin(SOCKET sock, CRYPT_SESSION sess, const char* resp sockprintf(sock, client->protocol, sess, "%s", resp); } -static void pop3_thread(void* arg) +static bool pop3_client_thread(pop3_t* pop3) { char* p; char str[128]; @@ -1021,7 +1026,6 @@ static void pop3_thread(void* arg) user_t user; client_t client; mail_t* mail; - pop3_t pop3=*(pop3_t*)arg; login_attempt_t attempted; CRYPT_SESSION session = -1; BOOL nodelay=TRUE; @@ -1031,74 +1035,55 @@ static void pop3_thread(void* arg) int stat; union xp_sockaddr server_addr; - SetThreadName("sbbs/pop3"); - thread_up(TRUE /* setuid */); - - free(arg); + socket = pop3->socket; - socket=pop3.socket; - - client.protocol = pop3.tls_port ? "POP3S" : "POP3"; + client.protocol = pop3->tls_port ? "POP3S" : "POP3"; if(startup->options&MAIL_OPT_DEBUG_POP3) lprintf(LOG_DEBUG,"%04d %s session thread started", socket, client.protocol); -#ifdef _WIN32 - if(startup->pop3_sound[0] && !sound_muted(&scfg)) - PlaySound(startup->pop3_sound, NULL, SND_ASYNC|SND_FILENAME); -#endif - socklen_t addr_len = sizeof(server_addr); if((i=getsockname(socket, &server_addr.addr, &addr_len))!=0) { lprintf(LOG_CRIT,"%04d %s !ERROR %d (%d) getting address/port" ,socket, client.protocol, i, ERROR_VALUE); - mail_close_socket(&socket, &session); - thread_down(); - return; + return false; } - inet_addrtop(&pop3.client_addr, host_ip, sizeof(host_ip)); + inet_addrtop(&pop3->client_addr, host_ip, sizeof(host_ip)); inet_addrtop(&server_addr, server_ip, sizeof(server_ip)); if(startup->options&MAIL_OPT_DEBUG_POP3) lprintf(LOG_INFO,"%04d %s [%s] connection accepted on %s port %u from port %u" - ,socket, client.protocol, host_ip, server_ip, inet_addrport(&server_addr), inet_addrport(&pop3.client_addr)); + ,socket, client.protocol, host_ip, server_ip, inet_addrport(&server_addr), inet_addrport(&pop3->client_addr)); SAFECOPY(host_name, STR_NO_HOSTNAME); if(!(startup->options&MAIL_OPT_NO_HOST_LOOKUP)) { - getnameinfo(&pop3.client_addr.addr, pop3.client_addr_len, host_name, sizeof(host_name), NULL, 0, NI_NAMEREQD); + getnameinfo(&pop3->client_addr.addr, pop3->client_addr_len, host_name, sizeof(host_name), NULL, 0, NI_NAMEREQD); if(startup->options&MAIL_OPT_DEBUG_POP3) lprintf(LOG_INFO,"%04d %s [%s] Hostname: %s", socket, client.protocol, host_ip, host_name); } - if (pop3.tls_port) { + if (pop3->tls_port) { if (get_ssl_cert(&scfg, &estr, &level) == -1) { if (estr) { lprintf(level, "%04d %s [%s] !Failure getting certificate: %s", socket, client.protocol, host_ip, estr); free_crypt_attrstr(estr); } - mail_close_socket(&socket, &session); - thread_down(); - return; + return false; } if ((stat=cryptCreateSession(&session, CRYPT_UNUSED, CRYPT_SESSION_SSL_SERVER)) != CRYPT_OK) { GCESH(stat, client.protocol, socket, host_ip, CRYPT_UNUSED, "creating session"); - mail_close_socket(&socket, &session); - thread_down(); - return; + return false; } + pop3->session = session; if ((stat=cryptSetAttribute(session, CRYPT_SESSINFO_SSL_OPTIONS, CRYPT_SSLOPTION_DISABLE_CERTVERIFY)) != CRYPT_OK) { GCESH(stat, client.protocol, socket, host_ip, session, "disabling certificate verification"); - mail_close_socket(&socket, &session); - thread_down(); - return; + return false; } lock_ssl_cert(); if ((stat=cryptSetAttribute(session, CRYPT_SESSINFO_PRIVATEKEY, scfg.tls_certificate)) != CRYPT_OK) { unlock_ssl_cert(); GCESH(stat, client.protocol, socket, host_ip, session, "setting private key"); - mail_close_socket(&socket, &session); - thread_down(); - return; + return false; } nodelay = TRUE; setsockopt(socket,IPPROTO_TCP,TCP_NODELAY,(char*)&nodelay,sizeof(nodelay)); @@ -1107,24 +1092,18 @@ static void pop3_thread(void* arg) if ((stat = cryptSetAttribute(session, CRYPT_SESSINFO_NETWORKSOCKET, socket)) != CRYPT_OK) { unlock_ssl_cert(); GCESH(stat, client.protocol, socket, host_ip, session, "setting session socket"); - mail_close_socket(&socket, &session); - thread_down(); - return; + return false; } if ((stat = cryptSetAttribute(session, CRYPT_SESSINFO_ACTIVE, 1)) != CRYPT_OK) { unlock_ssl_cert(); GCESH(stat, client.protocol, socket, host_ip, session, "setting session active"); - mail_close_socket(&socket, &session); - thread_down(); - return; + return false; } unlock_ssl_cert(); if (startup->max_inactivity) { if (cryptSetAttribute(session, CRYPT_OPTION_NET_READTIMEOUT, startup->max_inactivity) != CRYPT_OK) { GCESH(stat, client.protocol, socket, host_ip, session, "setting read timeout"); - mail_close_socket(&socket, &session); - thread_down(); - return; + return false; } } } @@ -1139,35 +1118,28 @@ static void pop3_thread(void* arg) else lprintf(LOG_NOTICE,"%04d %s [%s] !CLIENT IP ADDRESS BLOCKED",socket, client.protocol, host_ip); sockprintf(socket,client.protocol,session,"-ERR Access denied."); - mail_close_socket(&socket, &session); - thread_down(); - return; + return false; } if(trashcan(&scfg,host_name,"host")) { lprintf(LOG_NOTICE,"%04d %s [%s] !CLIENT HOSTNAME BLOCKED: %s" ,socket, client.protocol, host_ip, host_name); sockprintf(socket,client.protocol,session,"-ERR Access denied."); - mail_close_socket(&socket, &session); - thread_down(); - return; + return false; } - (void)protected_uint32_adjust(&active_clients, 1); - update_clients(); - /* Initialize client display */ client.size=sizeof(client); client.time=time32(NULL); SAFECOPY(client.addr,host_ip); SAFECOPY(client.host,host_name); - client.port=inet_addrport(&pop3.client_addr); + client.port=inet_addrport(&pop3->client_addr); SAFECOPY(client.user, STR_UNKNOWN_USER); client.usernum = 0; client_on(socket,&client,FALSE /* update */); if(startup->login_attempt.throttle - && (login_attempts=loginAttempts(startup->login_attempt_list, &pop3.client_addr)) > 1) { + && (login_attempts=loginAttempts(startup->login_attempt_list, &pop3->client_addr)) > 1) { lprintf(LOG_DEBUG,"%04d %s [%s] Throttling suspicious connection (%lu login attempts)" ,socket, client.protocol, host_ip, login_attempts); mswait(login_attempts*startup->login_attempt.throttle); @@ -1220,6 +1192,7 @@ static void pop3_thread(void* arg) buf[0] = 0; break; } + pop3->session = session; if ((stat=cryptSetAttribute(session, CRYPT_SESSINFO_SSL_OPTIONS, CRYPT_SSLOPTION_DISABLE_CERTVERIFY)) != CRYPT_OK) { GCESH(stat, client.protocol, socket, host_ip, session, "disabling certificate verification"); buf[0] = 0; @@ -1297,7 +1270,7 @@ static void pop3_thread(void* arg) else lprintf(LOG_NOTICE,"%04d %s [%s] !UNKNOWN USER: '%s'" ,socket, client.protocol, host_ip, username); - badlogin(socket, session, pop_auth_error, username, password, &client, &pop3.client_addr); + badlogin(socket, session, pop_auth_error, username, password, &client, &pop3->client_addr); break; } if((i=getuserdat(&scfg, &user))!=0) { @@ -1324,7 +1297,7 @@ static void pop3_thread(void* arg) lprintf(LOG_DEBUG,"%04d !POP3 calc digest: %s",socket,str); lprintf(LOG_DEBUG,"%04d !POP3 resp digest: %s",socket,response); #endif - badlogin(socket, session, pop_auth_error, username, response, &client, &pop3.client_addr); + badlogin(socket, session, pop_auth_error, username, response, &client, &pop3->client_addr); break; } } else if(stricmp(password,user.pass)) { @@ -1334,12 +1307,12 @@ static void pop3_thread(void* arg) else lprintf(LOG_NOTICE,"%04d %s [%s] !FAILED Password attempt for user %s" ,socket, client.protocol, host_ip, username); - badlogin(socket, session, pop_auth_error, username, password, &client, &pop3.client_addr); + badlogin(socket, session, pop_auth_error, username, password, &client, &pop3->client_addr); break; } if(user.pass[0]) { - loginSuccess(startup->login_attempt_list, &pop3.client_addr); + loginSuccess(startup->login_attempt_list, &pop3->client_addr); listAddNodeData(¤t_logins, client.addr, strlen(client.addr) + 1, socket, LAST_NODE); } @@ -1739,10 +1712,10 @@ static void pop3_thread(void* arg) if(activity) { if(user.number) lprintf(LOG_INFO,"%04d %s <%s> logged-out from port %u on %s [%s]" - ,socket, client.protocol, user.alias, inet_addrport(&pop3.client_addr), host_name, host_ip); + ,socket, client.protocol, user.alias, inet_addrport(&pop3->client_addr), host_name, host_ip); else lprintf(LOG_INFO,"%04d %s [%s] client disconnected from port %u on %s" - ,socket, client.protocol, host_ip, inet_addrport(&pop3.client_addr), host_name); + ,socket, client.protocol, host_ip, inet_addrport(&pop3->client_addr), host_name); } /* Free up resources here */ @@ -1757,15 +1730,36 @@ static void pop3_thread(void* arg) update_clients(); client_off(socket); - SOCKET sock = socket; - mail_close_socket(&socket, &session); /* Must be last */ { int32_t remain = thread_down(); if(startup->options&MAIL_OPT_DEBUG_POP3) lprintf(LOG_DEBUG,"%04d %s [%s] session thread terminated (%u threads remain, %lu clients served)" - ,sock, client.protocol, host_ip, remain, ++stats.pop3_served); + ,socket, client.protocol, host_ip, remain, ++stats.pop3_served); } + return true; +} + +// Wrapper for pop3_client_thread() that does some basic resource management +static void pop3_thread(void* arg) +{ + pop3_t pop3 = *(pop3_t*)arg; + + SetThreadName("sbbs/pop3"); + thread_up(TRUE /* setuid */); + + free(arg); + + (void)protected_uint32_adjust(&active_clients, 1); + update_clients(); + + if (!pop3_client_thread(&pop3)) + thread_down(); + + (void)protected_uint32_adjust(&active_clients, -1); + update_clients(); + + mail_close_socket(&pop3.socket, &pop3.session); } static in_addr_t rblchk(SOCKET sock, const char* prot, union xp_sockaddr *addr, const char* rbl_addr) @@ -2808,7 +2802,7 @@ char *with_clauses[] = { "ESMTPSA" // WITH_TLS | WITH_AUTH | WITH_ESMTP }; -static void smtp_thread(void* arg) +static bool smtp_client_thread(smtp_t* smtp) { int i,j; int rd; @@ -2898,10 +2892,8 @@ static void smtp_thread(void* arg) node_t node; client_t client; char client_id[128]; - smtp_t smtp=*(smtp_t*)arg; union xp_sockaddr server_addr; IN_ADDR dnsbl_result; - BOOL* mailproc_to_match; int mailproc_match; JSRuntime* js_runtime=NULL; JSContext* js_cx=NULL; @@ -2936,14 +2928,9 @@ static void smtp_thread(void* arg) } cmd = SMTP_CMD_NONE; - SetThreadName("sbbs/smtp"); - thread_up(TRUE /* setuid */); - - free(arg); + socket = smtp->socket; - socket=smtp.socket; - - client.protocol = smtp.tls_port ? "SMTPS" : "SMTP"; + client.protocol = smtp->tls_port ? "SMTPS" : "SMTP"; lprintf(LOG_DEBUG,"%04d %s Session thread started", socket, client.protocol); @@ -2955,35 +2942,47 @@ static void smtp_thread(void* arg) addr_len=sizeof(server_addr); - if(smtp.tls_port) { + if((i=getsockname(socket, &server_addr.addr, &addr_len))!=0) { + lprintf(LOG_CRIT, "%04d %s !ERROR %d (%d) getting address/port" + ,socket, client.protocol, i, ERROR_VALUE); + return false; + } + + inet_addrtop(&smtp->client_addr,host_ip,sizeof(host_ip)); + inet_addrtop(&server_addr,server_ip,sizeof(server_ip)); + + lprintf(LOG_INFO,"%04d %s [%s] Connection accepted on %s port %u from port %u" + ,socket, client.protocol, host_ip, server_ip, inet_addrport(&server_addr), inet_addrport(&smtp->client_addr)); + SAFEPRINTF(client_id, "[%s]", host_ip); + + SAFECOPY(host_name, STR_NO_HOSTNAME); + if(!(startup->options&MAIL_OPT_NO_HOST_LOOKUP)) { + getnameinfo(&smtp->client_addr.addr, smtp->client_addr_len, host_name, sizeof(host_name), NULL, 0, NI_NAMEREQD); + lprintf(LOG_INFO,"%04d %s %s Hostname: %s", socket, client.protocol, client_id, host_name); + } + + if(smtp->tls_port) { if (get_ssl_cert(&scfg, &estr, &level) == -1) { if (estr) { lprintf(level, "%04d %s !%s", socket, client.protocol, estr); free_crypt_attrstr(estr); } - mail_close_socket(&socket, &session); - thread_down(); - return; + return false; } if ((cstat = cryptCreateSession(&session, CRYPT_UNUSED, CRYPT_SESSION_SSL_SERVER)) != CRYPT_OK) { - GCES(cstat, client.protocol, socket, CRYPT_UNUSED, "creating session"); - mail_close_socket(&socket, &session); - thread_down(); - return; + GCESH(cstat, client.protocol, socket, host_ip, CRYPT_UNUSED, "creating session"); + return false; } + smtp->session = session; if ((cstat = cryptSetAttribute(session, CRYPT_SESSINFO_SSL_OPTIONS, CRYPT_SSLOPTION_DISABLE_CERTVERIFY)) != CRYPT_OK) { - GCES(cstat, client.protocol, socket, CRYPT_UNUSED, "disabling certificate verification"); - mail_close_socket(&socket, &session); - thread_down(); - return; + GCESH(cstat, client.protocol, socket, host_ip, CRYPT_UNUSED, "disabling certificate verification"); + return false; } lock_ssl_cert(); if ((cstat = cryptSetAttribute(session, CRYPT_SESSINFO_PRIVATEKEY, scfg.tls_certificate)) != CRYPT_OK) { unlock_ssl_cert(); - GCES(cstat, client.protocol, socket, CRYPT_UNUSED, "setting private key"); - mail_close_socket(&socket, &session); - thread_down(); - return; + GCESH(cstat, client.protocol, socket, host_ip, CRYPT_UNUSED, "setting private key"); + return false; } nodelay = TRUE; setsockopt(socket,IPPROTO_TCP,TCP_NODELAY,(char*)&nodelay,sizeof(nodelay)); @@ -2991,68 +2990,29 @@ static void smtp_thread(void* arg) ioctlsocket(socket,FIONBIO,&nb); if ((cstat = cryptSetAttribute(session, CRYPT_SESSINFO_NETWORKSOCKET, socket)) != CRYPT_OK) { unlock_ssl_cert(); - GCES(cstat, client.protocol, socket, CRYPT_UNUSED, "setting network socket"); - mail_close_socket(&socket, &session); - thread_down(); - return; + GCESH(cstat, client.protocol, socket, host_ip, CRYPT_UNUSED, "setting network socket"); + return false; } if ((cstat = cryptSetAttribute(session, CRYPT_SESSINFO_ACTIVE, 1)) != CRYPT_OK) { unlock_ssl_cert(); - GCES(cstat, client.protocol, socket, CRYPT_UNUSED, "setting session active"); - mail_close_socket(&socket, &session); - thread_down(); - return; + GCESH(cstat, client.protocol, socket, host_ip, CRYPT_UNUSED, "setting session active"); + return false; } unlock_ssl_cert(); if (startup->max_inactivity) { if ((cstat = cryptSetAttribute(session, CRYPT_OPTION_NET_READTIMEOUT, startup->max_inactivity)) != CRYPT_OK) { - GCES(cstat, client.protocol, socket, CRYPT_UNUSED, "setting read timeout"); - mail_close_socket(&socket, &session); - thread_down(); - return; + GCESH(cstat, client.protocol, socket, host_ip, CRYPT_UNUSED, "setting read timeout"); + return false; } } } - if((i=getsockname(socket, &server_addr.addr, &addr_len))!=0) { - lprintf(LOG_CRIT,"%04d %s !ERROR %d (%d) getting address/port" - ,socket, client.protocol, i, ERROR_VALUE); - sockprintf(socket,client.protocol,session,smtp_error, "getsockname failure"); - mail_close_socket(&socket, &session); - thread_down(); - return; - } - - if((mailproc_to_match=malloc(sizeof(BOOL)*mailproc_count))==NULL) { - lprintf(LOG_CRIT,"%04d %s !ERROR allocating memory for mailproc_to_match", socket, client.protocol); - sockprintf(socket,client.protocol,session,smtp_error, "malloc failure"); - mail_close_socket(&socket, &session); - thread_down(); - return; - } - memset(mailproc_to_match,FALSE,sizeof(BOOL)*mailproc_count); - memset(&smb,0,sizeof(smb)); memset(&msg,0,sizeof(msg)); memset(&spam,0,sizeof(spam)); memset(&user,0,sizeof(user)); memset(&relay_user,0,sizeof(relay_user)); - inet_addrtop(&smtp.client_addr,host_ip,sizeof(host_ip)); - inet_addrtop(&server_addr,server_ip,sizeof(server_ip)); - - lprintf(LOG_INFO,"%04d %s [%s] Connection accepted on %s port %u from port %u" - ,socket, client.protocol, host_ip, server_ip, inet_addrport(&server_addr), inet_addrport(&smtp.client_addr)); - SAFEPRINTF(client_id, "[%s]", host_ip); - - SAFECOPY(host_name, STR_NO_HOSTNAME); - if(!(startup->options&MAIL_OPT_NO_HOST_LOOKUP)) { - getnameinfo(&smtp.client_addr.addr, smtp.client_addr_len, host_name, sizeof(host_name), NULL, 0, NI_NAMEREQD); - lprintf(LOG_INFO,"%04d %s %s Hostname: %s", socket, client.protocol, client_id, host_name); - } - (void)protected_uint32_adjust(&active_clients, 1); - update_clients(); - SAFECOPY(hello_name,host_name); SAFEPRINTF(spam_bait,"%sspambait.cfg",scfg.ctrl_dir); @@ -3068,12 +3028,7 @@ static void smtp_thread(void* arg) char ban_duration[128]; lprintf(LOG_NOTICE, "%04d %s [%s] !TEMPORARY BAN (%lu login attempts, last: %s) - remaining: %s" ,socket, client.protocol, host_ip, attempted.count-attempted.dupes, attempted.user, seconds_to_str(banned, ban_duration)); - mail_close_socket(&socket, &session); - thread_down(); - (void)protected_uint32_adjust(&active_clients, -1); - update_clients(); - free(mailproc_to_match); - return; + return false; } spam_block_exempt = findstr(host_ip,spam_block_exemptions) || findstr(host_name,spam_block_exemptions); @@ -3082,28 +3037,18 @@ static void smtp_thread(void* arg) lprintf(LOG_NOTICE,"%04d %s !CLIENT IP ADDRESS BLOCKED: %s (%lu total)" ,socket, client.protocol, host_ip, ++stats.sessions_refused); sockprintf(socket,client.protocol,session,"550 CLIENT IP ADDRESS BLOCKED: %s", host_ip); - mail_close_socket(&socket, &session); - thread_down(); - (void)protected_uint32_adjust(&active_clients, -1); - update_clients(); - free(mailproc_to_match); - return; + return false; } if(trashcan(&scfg,host_name,"host")) { lprintf(LOG_NOTICE,"%04d %s [%s] !CLIENT HOSTNAME BLOCKED: %s (%lu total)" ,socket, client.protocol, host_ip, host_name, ++stats.sessions_refused); sockprintf(socket,client.protocol,session,"550 CLIENT HOSTNAME BLOCKED: %s", host_name); - mail_close_socket(&socket, &session); - thread_down(); - (void)protected_uint32_adjust(&active_clients, -1); - update_clients(); - free(mailproc_to_match); - return; + return false; } /* SPAM Filters (mail-abuse.org) */ - dnsbl_result.s_addr = dns_blacklisted(socket,client.protocol,&smtp.client_addr,host_name,dnsbl,dnsbl_ip); + dnsbl_result.s_addr = dns_blacklisted(socket,client.protocol,&smtp->client_addr,host_name,dnsbl,dnsbl_ip); if(dnsbl_result.s_addr) { lprintf(LOG_NOTICE,"%04d %s [%s] BLACKLISTED SERVER on %s: %s = %s" ,socket, client.protocol, dnsbl_ip, dnsbl, host_name, inet_ntoa(dnsbl_result)); @@ -3115,12 +3060,7 @@ static void smtp_thread(void* arg) ,dnsbl_ip, dnsbl); lprintf(LOG_NOTICE,"%04d %s !REFUSED SESSION from blacklisted server (%lu total)" ,socket, client.protocol, ++stats.sessions_refused); - mail_close_socket(&socket, &session); - thread_down(); - (void)protected_uint32_adjust(&active_clients, -1); - update_clients(); - free(mailproc_to_match); - return; + return false; } } } @@ -3130,12 +3070,7 @@ static void smtp_thread(void* arg) lprintf(LOG_WARNING,"%04d %s [%s] !MAIL BASE LOCKED: %s" ,socket, client.protocol, host_ip, smb.last_error); sockprintf(socket,client.protocol,session, smtp_error, "mail base locked"); - mail_close_socket(&socket, &session); - thread_down(); - (void)protected_uint32_adjust(&active_clients, -1); - update_clients(); - free(mailproc_to_match); - return; + return false; } SAFEPRINTF(spam.file,"%sspam",scfg.data_dir); spam.retry_time=scfg.smb_retry_time; @@ -3154,12 +3089,7 @@ static void smtp_thread(void* arg) lprintf(LOG_CRIT,"%04d %s [%s] !ERROR %d creating recipient list: %s" ,socket, client.protocol, host_ip, errno, rcptlst_fname); sockprintf(socket,client.protocol,session,smtp_error, "fopen error"); - mail_close_socket(&socket, &session); - thread_down(); - (void)protected_uint32_adjust(&active_clients, -1); - update_clients(); - free(mailproc_to_match); - return; + return false; } if(trashcan(&scfg,host_name,"smtpspy") @@ -3175,18 +3105,25 @@ static void smtp_thread(void* arg) client.time=time32(NULL); SAFECOPY(client.addr,host_ip); SAFECOPY(client.host,host_name); - client.port=inet_addrport(&smtp.client_addr); + client.port=inet_addrport(&smtp->client_addr); SAFECOPY(client.user, STR_UNKNOWN_USER); client.usernum = 0; client_on(socket,&client,FALSE /* update */); if(startup->login_attempt.throttle - && (login_attempts=loginAttempts(startup->login_attempt_list, &smtp.client_addr)) > 1) { + && (login_attempts=loginAttempts(startup->login_attempt_list, &smtp->client_addr)) > 1) { lprintf(LOG_DEBUG,"%04d %s Throttling suspicious connection from: %s (%lu login attempts)" ,socket, client.protocol, host_ip, login_attempts); mswait(login_attempts*startup->login_attempt.throttle); } + BOOL* mailproc_to_match = calloc(sizeof(*mailproc_to_match), mailproc_count); + if(mailproc_to_match == NULL) { + lprintf(LOG_CRIT,"%04d %s !ERROR allocating memory for mailproc_to_match", socket, client.protocol); + sockprintf(socket,client.protocol,session,smtp_error, "malloc failure"); + return false; + } + /* SMTP session active: */ sockprintf(socket,client.protocol,session,"220 %s Synchronet %s Server %s%c-%s Ready" @@ -3253,7 +3190,7 @@ static void smtp_thread(void* arg) p=strchr(sender_addr,'@'); memset(&ai, 0, sizeof(ai)); ai.ai_flags = AI_PASSIVE; - ai.ai_family = smtp.client_addr.addr.sa_family; + ai.ai_family = smtp->client_addr.addr.sa_family; if(getaddrinfo(p+1, NULL, &ai, &res) != 0) p=NULL; else { @@ -3932,7 +3869,7 @@ static void smtp_thread(void* arg) " for %s; %s\r\n" " (envelope-from %s)" ,host_name,hello_name - ,smtp.client_addr.addr.sa_family==AF_INET6?"IPv6: ":"" + ,smtp->client_addr.addr.sa_family==AF_INET6?"IPv6: ":"" ,host_ip ,server_host_name() ,server_addr.addr.sa_family==AF_INET6?"IPv6: ":"" @@ -4151,27 +4088,27 @@ static void smtp_thread(void* arg) sockprintf(socket,client.protocol,session,"334 VXNlcm5hbWU6"); /* Base64-encoded "Username:" */ if((rd=sockreadline(socket, client.protocol, session, buf, sizeof(buf)))<1) { lprintf(LOG_WARNING,"%04d %s %s !Missing AUTH LOGIN username argument", socket, client.protocol, client_id); - badlogin(socket, session, badarg_rsp, NULL, NULL, &client, &smtp.client_addr); + badlogin(socket, session, badarg_rsp, NULL, NULL, &client, &smtp->client_addr); continue; } if(startup->options&MAIL_OPT_DEBUG_RX_RSP) lprintf(LOG_DEBUG,"%04d %s %s RX: %s", socket, client.protocol, client_id, buf); if(b64_decode(user_name,sizeof(user_name),buf,rd)<1 || str_has_ctrl(user_name)) { lprintf(LOG_WARNING,"%04d %s %s !Bad AUTH LOGIN username argument", socket, client.protocol, client_id); - badlogin(socket, session, badarg_rsp, NULL, NULL, &client, &smtp.client_addr); + badlogin(socket, session, badarg_rsp, NULL, NULL, &client, &smtp->client_addr); continue; } sockprintf(socket,client.protocol,session,"334 UGFzc3dvcmQ6"); /* Base64-encoded "Password:" */ if((rd=sockreadline(socket, client.protocol, session, buf, sizeof(buf)))<1) { lprintf(LOG_WARNING,"%04d %s %s !Missing AUTH LOGIN password argument", socket, client.protocol, client_id); - badlogin(socket, session, badarg_rsp, user_name, NULL, &client, &smtp.client_addr); + badlogin(socket, session, badarg_rsp, user_name, NULL, &client, &smtp->client_addr); continue; } if(startup->options&MAIL_OPT_DEBUG_RX_RSP) lprintf(LOG_DEBUG,"%04d %s %s RX: %s", socket, client.protocol, client_id, buf); if(b64_decode(user_pass,sizeof(user_pass),buf,rd)<1 || str_has_ctrl(user_pass)) { lprintf(LOG_WARNING,"%04d %s %s !Bad AUTH LOGIN password argument", socket, client.protocol, client_id); - badlogin(socket, session, badarg_rsp, user_name, NULL, &client, &smtp.client_addr); + badlogin(socket, session, badarg_rsp, user_name, NULL, &client, &smtp->client_addr); continue; } } else { /* AUTH PLAIN b64(<username>\0<user-id>\0<password>) */ @@ -4179,13 +4116,13 @@ static void smtp_thread(void* arg) SKIP_WHITESPACE(p); if(*p==0) { lprintf(LOG_WARNING,"%04d %s %s !Missing AUTH PLAIN argument", socket, client.protocol, client_id); - badlogin(socket, session, badarg_rsp, NULL, NULL, &client, &smtp.client_addr); + badlogin(socket, session, badarg_rsp, NULL, NULL, &client, &smtp->client_addr); continue; } ZERO_VAR(tmp); if(b64_decode(tmp,sizeof(tmp),p,strlen(p))<1 || str_has_ctrl(tmp)) { lprintf(LOG_WARNING,"%04d %s %s !Bad AUTH PLAIN argument", socket, client.protocol, client_id); - badlogin(socket, session, badarg_rsp, NULL, NULL, &client, &smtp.client_addr); + badlogin(socket, session, badarg_rsp, NULL, NULL, &client, &smtp->client_addr); continue; } p=tmp; @@ -4193,7 +4130,7 @@ static void smtp_thread(void* arg) p++; /* skip NULL */ if(*p==0) { lprintf(LOG_WARNING,"%04d %s %s !Missing AUTH PLAIN user-id argument", socket, client.protocol, client_id); - badlogin(socket, session, badarg_rsp, NULL, NULL, &client, &smtp.client_addr); + badlogin(socket, session, badarg_rsp, NULL, NULL, &client, &smtp->client_addr); continue; } SAFECOPY(user_name,p); @@ -4201,7 +4138,7 @@ static void smtp_thread(void* arg) p++; /* skip NULL */ if(*p==0) { lprintf(LOG_WARNING,"%04d %s %s !Missing AUTH PLAIN password argument", socket, client.protocol, client_id); - badlogin(socket, session, badarg_rsp, user_name, NULL, &client, &smtp.client_addr); + badlogin(socket, session, badarg_rsp, user_name, NULL, &client, &smtp->client_addr); continue; } SAFECOPY(user_pass,p); @@ -4214,7 +4151,7 @@ static void smtp_thread(void* arg) else lprintf(LOG_WARNING,"%04d %s %s !UNKNOWN USER: '%s'" ,socket, client.protocol, client_id, user_name); - badlogin(socket, session, badauth_rsp, user_name, user_pass, &client, &smtp.client_addr); + badlogin(socket, session, badauth_rsp, user_name, user_pass, &client, &smtp->client_addr); break; } if((i=getuserdat(&scfg, &relay_user))!=0) { @@ -4236,12 +4173,12 @@ static void smtp_thread(void* arg) else lprintf(LOG_WARNING,"%04d %s %s !FAILED Password attempt for user %s" ,socket, client.protocol, client_id, user_name); - badlogin(socket, session, badauth_rsp, user_name, user_pass, &client, &smtp.client_addr); + badlogin(socket, session, badauth_rsp, user_name, user_pass, &client, &smtp->client_addr); break; } if(relay_user.pass[0]) { - loginSuccess(startup->login_attempt_list, &smtp.client_addr); + loginSuccess(startup->login_attempt_list, &smtp->client_addr); listAddNodeData(¤t_logins, client.addr, strlen(client.addr) + 1, socket, LAST_NODE); } @@ -4298,7 +4235,7 @@ static void smtp_thread(void* arg) if((relay_user.number = find_login_id(&scfg, user_name))==0) { lprintf(LOG_WARNING,"%04d %s %s !UNKNOWN USER: '%s'" ,socket, client.protocol, client_id, user_name); - badlogin(socket, session, badauth_rsp, user_name, NULL, &client, &smtp.client_addr); + badlogin(socket, session, badauth_rsp, user_name, NULL, &client, &smtp->client_addr); break; } if((i=getuserdat(&scfg, &relay_user))!=0) { @@ -4335,12 +4272,12 @@ static void smtp_thread(void* arg) lprintf(LOG_DEBUG,"%04d !SMTP resp digest: %s" ,socket,p); #endif - badlogin(socket, session, badauth_rsp, user_name, p, &client, &smtp.client_addr); + badlogin(socket, session, badauth_rsp, user_name, p, &client, &smtp->client_addr); break; } if(relay_user.pass[0]) { - loginSuccess(startup->login_attempt_list, &smtp.client_addr); + loginSuccess(startup->login_attempt_list, &smtp->client_addr); listAddNodeData(¤t_logins, client.addr, strlen(client.addr) + 1, socket, LAST_NODE); } @@ -4992,12 +4929,13 @@ static void smtp_thread(void* arg) continue; } if ((cstat=cryptCreateSession(&session, CRYPT_UNUSED, CRYPT_SESSION_SSL_SERVER)) != CRYPT_OK) { - GCES(cstat, "SMTPS", socket, CRYPT_UNUSED, "creating TLS session"); + GCESH(cstat, "SMTPS", socket, host_ip, CRYPT_UNUSED, "creating TLS session"); sockprintf(socket, client.protocol, session, "454 TLS not available"); continue; } + smtp->session = session; if ((cstat=cryptSetAttribute(session, CRYPT_SESSINFO_SSL_OPTIONS, CRYPT_SSLOPTION_DISABLE_CERTVERIFY)) != CRYPT_OK) { - GCES(cstat, "SMTPS", socket, session, "disabling certificate verification"); + GCESH(cstat, "SMTPS", socket, host_ip, session, "disabling certificate verification"); cryptDestroySession(session); session = -1; sockprintf(socket, client.protocol, session, "454 TLS not available"); @@ -5006,7 +4944,7 @@ static void smtp_thread(void* arg) lock_ssl_cert(); if ((cstat=cryptSetAttribute(session, CRYPT_SESSINFO_PRIVATEKEY, scfg.tls_certificate)) != CRYPT_OK) { unlock_ssl_cert(); - GCES(cstat, "SMTPS", socket, session, "setting private key"); + GCESH(cstat, "SMTPS", socket, host_ip, session, "setting private key"); lprintf(LOG_ERR, "%04d SMTPS %s !Unable to set private key", socket, client_id); cryptDestroySession(session); session = -1; @@ -5019,7 +4957,7 @@ static void smtp_thread(void* arg) ioctlsocket(socket,FIONBIO,&nb); if ((cstat = cryptSetAttribute(session, CRYPT_SESSINFO_NETWORKSOCKET, socket)) != CRYPT_OK) { unlock_ssl_cert(); - GCES(cstat, "SMTPS", socket, session, "setting network socket"); + GCESH(cstat, "SMTPS", socket, host_ip, session, "setting network socket"); cryptDestroySession(session); session = -1; sockprintf(socket, client.protocol, session, "454 TLS not available"); @@ -5028,13 +4966,13 @@ static void smtp_thread(void* arg) sockprintf(socket, client.protocol, -1, "220 Ready to start TLS"); if ((cstat=cryptSetAttribute(session, CRYPT_SESSINFO_ACTIVE, 1)) != CRYPT_OK) { unlock_ssl_cert(); - GCES(cstat, "SMTPS", socket, session, "setting session active"); + GCESH(cstat, "SMTPS", socket, host_ip, session, "setting session active"); break; } unlock_ssl_cert(); if (startup->max_inactivity) { if ((cstat=cryptSetAttribute(session, CRYPT_OPTION_NET_READTIMEOUT, startup->max_inactivity)) != CRYPT_OK) { - GCES(cstat, "SMTPS", socket, session, "setting read timeout"); + GCESH(cstat, "SMTPS", socket, host_ip, session, "setting read timeout"); break; } } @@ -5074,16 +5012,36 @@ static void smtp_thread(void* arg) PlaySound(startup->sound.logout, NULL, SND_ASYNC|SND_FILENAME); } #endif - SOCKET sock = socket; - mail_close_socket(&socket, &session); - /* Must be last */ { int32_t remain = thread_down(); lprintf(LOG_INFO,"%04d %s %s Session thread terminated (%u threads remain, %lu clients served)" - ,sock, client.protocol, client_id, remain, ++stats.smtp_served); + ,socket, client.protocol, client_id, remain, ++stats.smtp_served); } free(mailproc_to_match); + return true; +} + +// Wrapper for smtp_client_thread() that does some basic resource management +static void smtp_thread(void* arg) +{ + smtp_t smtp = *(smtp_t*)arg; + + SetThreadName("sbbs/smtp"); + thread_up(TRUE /* setuid */); + + free(arg); + + (void)protected_uint32_adjust(&active_clients, 1); + update_clients(); + + if (!smtp_client_thread(&smtp)) + thread_down(); + + (void)protected_uint32_adjust(&active_clients, -1); + update_clients(); + + mail_close_socket(&smtp.socket, &smtp.session); } BOOL bounce(SOCKET sock, smb_t* smb, smbmsg_t* msg, char* err, BOOL immediate) @@ -6384,6 +6342,7 @@ void mail_server(void* arg) continue; } + smtp->session = -1; smtp->socket=client_socket; memcpy(&smtp->client_addr, &client_addr, client_addr_len); smtp->client_addr_len=client_addr_len; @@ -6402,6 +6361,7 @@ void mail_server(void* arg) continue; } + pop3->session = -1; pop3->socket=client_socket; memcpy(&pop3->client_addr, &client_addr, client_addr_len); pop3->client_addr_len=client_addr_len;