Skip to content
Snippets Groups Projects
mailsrvr.c 202 KiB
Newer Older
/* Synchronet Mail (SMTP/POP3) server and sendmail threads */

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
 *																			*
 * This program is free software; you can redistribute it and/or			*
 * modify it under the terms of the GNU General Public License				*
 * as published by the Free Software Foundation; either version 2			*
 * of the License, or (at your option) any later version.					*
 * See the GNU General Public License for more details: gpl.txt or			*
 * http://www.fsf.org/copyleft/gpl.html										*
 *																			*
 * Anonymous FTP access to the most recent released source is available at	*
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
 *																			*
 * Anonymous CVS access to the development source and modification history	*
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * You are encouraged to submit any modifications (preferably in Unix diff	*
 * format) via e-mail to mods@synchro.net									*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

rswindell's avatar
rswindell committed
/* ANSI C Library headers */
deuce's avatar
deuce committed
#include <limits.h>			/* UINT_MAX */
rswindell's avatar
rswindell committed
#include <stdio.h>
#include <stdlib.h>			/* ltoa in GNU C lib */
#include <stdarg.h>			/* va_list */
#include <string.h>			/* strrchr */
#include <ctype.h>			/* isdigit */
#include <fcntl.h>			/* Open flags */
#include <errno.h>			/* errno */
rswindell's avatar
rswindell committed

/* Synchronet-specific headers */
#undef SBBS	/* this shouldn't be defined unless building sbbs.dll/libsbbs.so */
rswindell's avatar
rswindell committed
#include "mailsrvr.h"
#include "crc32.h"
#include "netwrap.h"	/* getNameServerList() */
deuce's avatar
deuce committed
#include "multisock.h"
#include "ssl.h"
#include "cryptlib.h"
rswindell's avatar
rswindell committed
/* Constants */
static const char*	server_name="Synchronet Mail Server";
#define FORWARD			"forward:"
#define NO_FORWARD		"local:"
int dns_getmx(char* name, char* mx, char* mx2
			  ,DWORD intf, DWORD ip_addr, BOOL use_tcp, int timeout);
#define pop_err			"-ERR"
#define ok_rsp			"250 OK"
#define auth_ok			"235 User Authenticated"
#define sys_error		"421 System error"
#define sys_unavail		"421 System unavailable, try again later"
#define insuf_stor		"452 Insufficient system storage"
#define badarg_rsp 		"501 Bad argument"
#define badseq_rsp		"503 Bad sequence of commands"
#define badauth_rsp		"535 Authentication failure"
#define badrsp_err		"%s replied with:\r\n\"%s\"\r\ninstead of the expected reply:\r\n\"%s ...\""
#define TIMEOUT_THREAD_WAIT		60		/* Seconds */
#define DNSBL_THROTTLE_VALUE	1000	/* Milliseconds */

#define STATUS_WFC	"Listening"

static mail_startup_t* startup=NULL;
static scfg_t	scfg;
deuce's avatar
deuce committed
static struct xpms_set	*mail_set=NULL;
static BOOL terminated=FALSE;
static protected_uint32_t active_clients;
static protected_uint32_t thread_count;
static volatile int		active_sendmail=0;
static volatile BOOL	sendmail_running=FALSE;
static volatile BOOL	terminate_server=FALSE;
static volatile BOOL	terminate_sendmail=FALSE;
static sem_t	sendmail_wakeup_sem;
static char		revision[16];
static str_list_t recycle_semfiles;
static str_list_t shutdown_semfiles;
static js_server_props_t js_server_props;
	volatile ulong	sockets;
	volatile ulong	errors;
	volatile ulong	crit_errors;
	volatile ulong	connections_ignored;
	volatile ulong	connections_refused;
	volatile ulong	connections_served;
	volatile ulong	pop3_served;
	volatile ulong	smtp_served;
	volatile ulong	sessions_refused;
	volatile ulong	msgs_ignored;
	volatile ulong	msgs_refused;
	volatile ulong	msgs_received;
rswindell's avatar
rswindell committed
	char		name[INI_MAX_VALUE_LEN];
rswindell's avatar
rswindell committed
	char		eval[INI_MAX_VALUE_LEN];
	BOOL		ignore_on_error;	/* Ignore mail message if cmdline fails */
	ulong		handled;			/* counter (for stats display) */

typedef struct {
	SOCKET			socket;
deuce's avatar
deuce committed
	union xp_sockaddr	client_addr;
	socklen_t		client_addr_len;
deuce's avatar
deuce committed
#define GCES(status, server, sock, sess, action) do {                             \
deuce's avatar
deuce committed
	char *GCES_estr;                                                               \
	int GCES_level;                                                                 \
deuce's avatar
deuce committed
	get_crypt_error_string(status, sess, &GCES_estr, action, &GCES_level);  \
deuce's avatar
deuce committed
	if (GCES_estr) {                                                                  \
		lprintf(GCES_level, "%04d %s %s", sock, server, GCES_estr);                     \
deuce's avatar
deuce committed
		free_crypt_attrstr(GCES_estr);                                                  \
deuce's avatar
deuce committed
#define GCESH(status, server, sock, host, sess, action) do {                      \
deuce's avatar
deuce committed
	char *GCES_estr;                                                               \
	int GCES_level;                                                                 \
deuce's avatar
deuce committed
	get_crypt_error_string(status, sess, &GCES_estr, action, &GCES_level);  \
deuce's avatar
deuce committed
	if (GCES_estr) {                                                                  \
		lprintf(GCES_level, "%04d %s [%s] %s", sock, server, host, GCES_estr);         \
deuce's avatar
deuce committed
		free_crypt_attrstr(GCES_estr);                                                  \
#if defined(__GNUC__)   // Catch printf-format errors with lprintf
static int lprintf(int level, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
#endif
static int lprintf(int level, const char *fmt, ...)
{
	va_list argptr;
	char sbuf[1024];

	va_start(argptr,fmt);
    vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
	sbuf[sizeof(sbuf)-1]=0;
    va_end(argptr);
		char errmsg[sizeof(sbuf)+16];
		SAFEPRINTF(errmsg, "mail %s", sbuf);
		errorlog(&scfg,startup==NULL ? NULL:startup->host_name,errmsg), stats.errors++;
		if(startup!=NULL && startup->errormsg!=NULL)
			startup->errormsg(startup->cbdata,level,errmsg);

	if(level <= LOG_CRIT)
		stats.crit_errors++;

    if(startup==NULL || startup->lputs==NULL || level > startup->log_level)
		return(0);

#if defined(_WIN32)
	if(IsBadCodePtr((FARPROC)startup->lputs))
		return(0);
#endif

    return(startup->lputs(startup->cbdata,level,sbuf));
Loading
Loading full blame...