Skip to content
Snippets Groups Projects
mailsrvr.c 116 KiB
Newer Older
				}
				msg.hdr.number=mail[msgnum-1].number;

				lprintf(LOG_INFO,"%04d POP3 %s retrieving message #%ld"
					,socket, user.alias, msg.hdr.number);

				if((i=smb_getmsgidx(&smb,&msg))!=0) {
					lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message index"
						,socket, i, smb.last_error);
					sockprintf(socket,"-ERR %d getting message index",i);
					continue;
				}
				if(msg.idx.attr&MSG_DELETE) {
					lprintf(LOG_WARNING,"%04d !POP3 ATTEMPT to retrieve DELETED message"
						,socket);
					sockprintf(socket,"-ERR message deleted");
					continue;
				}
				if((i=smb_lockmsghdr(&smb,&msg))!=0) {
					lprintf(LOG_WARNING,"%04d !POP3 ERROR %d (%s) locking message header #%lu"
						,socket, i, smb.last_error, msg.hdr.number);
					sockprintf(socket,"-ERR %d locking message header",i);
					continue; 
				}
				i=smb_getmsghdr(&smb,&msg);
				smb_unlockmsghdr(&smb,&msg);
				if(i!=0) {
					lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message header #%lu"
						,socket, i, smb.last_error, msg.hdr.number);
					sockprintf(socket,"-ERR %d getting message header",i);
					continue;
				}

				if((msgtxt=smb_getmsgtxt(&smb,&msg,GETMSGTXT_TAILS))==NULL) {
					smb_freemsgmem(&msg);
					lprintf(LOG_ERR,"%04d !POP3 ERROR (%s) retrieving message %lu text"
						,socket, smb.last_error, msg.hdr.number);
					sockprintf(socket,"-ERR retrieving message text");
					continue;
				}

				sockprintf(socket,"+OK message follows");
				lprintf(LOG_DEBUG,"%04d POP3 sending message text (%u bytes)"
					,socket,strlen(msgtxt));
				lines_sent=sockmsgtxt(socket,&msg,msgtxt,lines);
				/* if(startup->options&MAIL_OPT_DEBUG_POP3) */
				if(lines!=-1 && lines_sent<lines)	/* could send *more* lines */
					lprintf(LOG_ERR,"%04d !POP3 ERROR sending message text (sent %ld of %ld lines)"
					lprintf(LOG_DEBUG,"%04d POP3 message transfer complete (%lu lines)"
					msg.hdr.attr|=MSG_READ;
					msg.idx.attr=msg.hdr.attr;
					msg.hdr.netattr|=MSG_SENT;
					if((i=smb_lockmsghdr(&smb,&msg))!=0) 
						lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) locking message header #%lu"
							,socket, i, smb.last_error, msg.hdr.number);
					if((i=smb_putmsg(&smb,&msg))!=0)
						lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) marking message #%lu as read"
							,socket, i, smb.last_error, msg.hdr.number);
					smb_unlockmsghdr(&smb,&msg);
				}
				smb_freemsgmem(&msg);
				smb_freemsgtxt(msgtxt);
				continue;
			}
			if(!strnicmp(buf, "DELE ",5)) {
				p=buf+5;
				msgnum=atol(p);

				if(msgnum<1 || msgnum>msgs) {
					lprintf(LOG_WARNING,"%04d !POP3 %s ATTEMPTED to delete an INVALID message #%ld"
						,socket, user.alias, msgnum);
					sockprintf(socket,"-ERR no such message");
					continue;
				}
				msg.hdr.number=mail[msgnum-1].number;

				lprintf(LOG_INFO,"%04d POP3 %s deleting message #%ld"
					,socket, user.alias, msg.hdr.number);

				if((i=smb_getmsgidx(&smb,&msg))!=0) {
					lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message index"
						,socket, i, smb.last_error);
					sockprintf(socket,"-ERR %d getting message index",i);
					continue;
				}
				if((i=smb_lockmsghdr(&smb,&msg))!=0) {
					lprintf(LOG_WARNING,"%04d !POP3 ERROR %d (%s) locking message header #%lu"
						,socket, i, smb.last_error, msg.hdr.number);
					sockprintf(socket,"-ERR %d locking message header",i);
					continue; 
				}
				if((i=smb_getmsghdr(&smb,&msg))!=0) {
					smb_unlockmsghdr(&smb,&msg);
					lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message header #%lu"
						,socket, i, smb.last_error, msg.hdr.number);
					sockprintf(socket,"-ERR %d getting message header",i);
					continue;
				}
				msg.hdr.attr|=MSG_DELETE;
				msg.idx.attr=msg.hdr.attr;
				if((i=smb_putmsg(&smb,&msg))!=0) {
					smb_unlockmsghdr(&smb,&msg);
					smb_freemsgmem(&msg);
					lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) marking message as read"
						, socket, i, smb.last_error);
					sockprintf(socket,"-ERR %d marking message for deletion",i);
					continue;
				}
				if(msg.hdr.auxattr&MSG_FILEATTACH)
					delfattach(&scfg,&msg);
				smb_unlockmsghdr(&smb,&msg);
				smb_freemsgmem(&msg);
				sockprintf(socket,"+OK");
				if(startup->options&MAIL_OPT_DEBUG_POP3)
					lprintf(LOG_INFO,"%04d POP3 message deleted", socket);
			lprintf(LOG_WARNING,"%04d !POP3 UNSUPPORTED COMMAND from %s: '%s'"
				,socket, user.alias, buf);
			sockprintf(socket,"-ERR UNSUPPORTED COMMAND: %s",buf);
		}
		if(user.number)
			logoutuserdat(&scfg,&user,time(NULL),client.time);
		lprintf(LOG_INFO,"%04d POP3 %s logged out from port %u on %s [%s]"
			,socket, user.alias, ntohs(pop3.client_addr.sin_port), host_name, host_ip);

	status(STATUS_WFC);

	/* Free up resources here */
	if(mail!=NULL)
		freemail(mail);

	smb_freemsgmem(&msg);
	smb_close(&smb);

	if(active_clients)
		active_clients--, update_clients();
	client_off(socket);

	thread_down();
	if(startup->options&MAIL_OPT_DEBUG_POP3)
		lprintf(LOG_DEBUG,"%04d POP3 session thread terminated (%u threads remain, %lu clients served)"
static ulong rblchk(SOCKET sock, DWORD mail_addr_n, const char* rbl_addr)
{
	char		name[256];
	DWORD		mail_addr;

	mail_addr=ntohl(mail_addr_n);
	sprintf(name,"%ld.%ld.%ld.%ld.%s"
		,mail_addr&0xff
		,(mail_addr>>8)&0xff
		,(mail_addr>>16)&0xff
		,(mail_addr>>24)&0xff
		,rbl_addr
		);

	if(startup->options&MAIL_OPT_DNSBL_DEBUG)
		lprintf(LOG_DEBUG,"%04d SMTP DNSBL Query: %s",sock,name);
	if((host=gethostbyname(name))==NULL)
		return(0);
	dnsbl_result.s_addr = *((ulong*)host->h_addr_list[0]);
	lprintf(LOG_INFO,"%04d SMTP DNSBL Query: %s resolved to: %s"
		,sock,name,inet_ntoa(dnsbl_result));

	return(dnsbl_result.s_addr);
static ulong dns_blacklisted(SOCKET sock, IN_ADDR addr, char* host_name, char* list, char* dnsbl_ip)
{
	char	fname[MAX_PATH+1];
	char	str[256];
	char*	p;
	char*	tp;
	FILE*	fp;
	sprintf(fname,"%sdnsbl_exempt.cfg",scfg.ctrl_dir);
	if(findstr(inet_ntoa(addr),fname))
		return(FALSE);
	if(findstr(host_name,fname))
		return(FALSE);
	sprintf(fname,"%sdns_blacklist.cfg", scfg.ctrl_dir);
	if((fp=fopen(fname,"r"))==NULL)
		return(FALSE);

	while(!feof(fp) && !found) {
		if(fgets(str,sizeof(str),fp)==NULL)
		if(*p==';' || *p==0) /* comment or blank line */
			continue;

		sprintf(list,"%.100s",p);

		/* terminate */
		tp = p;
		found = rblchk(sock, addr.s_addr, p);
		strcpy(dnsbl_ip, inet_ntoa(addr));
static BOOL chk_email_addr(SOCKET socket, char* p, char* host_name, char* host_ip
						   ,char* to, char* from)
{
	char	addr[64];
	char	tmp[128];

	if(*p=='<') p++;		/* Skip '<' */
	SAFECOPY(addr,p);

	if(!trashcan(&scfg,addr,"email"))
		return(TRUE);

	lprintf(LOG_NOTICE,"%04d !SMTP BLOCKED SOURCE: %s"
		,socket, addr);
	sprintf(tmp,"Blocked source e-mail address: %s", addr);
	spamlog(&scfg, "SMTP", "REFUSED", tmp, host_name, host_ip, to, from);
	sockprintf(socket, "554 Sender not allowed.");

	return(FALSE);
}

static void signal_smtp_sem(void)
	if(scfg.smtpmail_sem[0]==0) 
	if((file=open(scfg.smtpmail_sem,O_WRONLY|O_CREAT|O_TRUNC))!=-1)
/*****************************************************************************/
/* Returns command line generated from instr with %c replacments             */
/*****************************************************************************/
static char* mailcmdstr(char* instr, char* msgpath, char* lstpath, char* errpath
						,char* host, char* ip, uint usernum, char* cmd)
{
	char	str[256];
    int		i,j,len;

    len=strlen(instr);
    for(i=j=0;i<len;i++) {
        if(instr[i]=='%') {
            i++;
            cmd[j]=0;
            switch(toupper(instr[i])) {
				case 'E':
					strcat(cmd,errpath);
					break;
				case 'H':
					strcat(cmd,host);
					break;
				case 'I':
					strcat(cmd,ip);
					break;
                case 'G':   /* Temp directory */
                    strcat(cmd,scfg.temp_dir);
                    break;
                case 'J':
                    strcat(cmd,scfg.data_dir);
                    break;
                case 'K':
                    strcat(cmd,scfg.ctrl_dir);
                    break;
				case 'L':
					strcat(cmd,lstpath);
					break;
				case 'F':
				case 'M':
					strcat(cmd,msgpath);
					break;
                case 'O':   /* SysOp */
                    strcat(cmd,scfg.sys_op);
                    break;
                case 'Q':   /* QWK ID */
                    strcat(cmd,scfg.sys_id);
                    break;
                case 'V':   /* Synchronet Version */
                    sprintf(str,"%s%c",VERSION,REVISION);
                    break;
                case 'Z':
                    strcat(cmd,scfg.text_dir);
                    break;
                case '!':   /* EXEC Directory */
                    strcat(cmd,scfg.exec_dir);
                    break;
                case '%':   /* %% for percent sign */
                    strcat(cmd,"%");
                    break;
				case '?':	/* Platform */
#ifdef __OS2__
					SAFECOPY(str,"OS2");
#else
					SAFECOPY(str,PLATFORM_DESC);
#endif
					strlwr(str);
					strcat(cmd,str);
					break;
				case 'U':	/* User number */
					sprintf(str,"%u",usernum);
					strcat(cmd,str);
					break;
                default:    /* unknown specification */
                    break; 
			}
            j=strlen(cmd); 
		}
        else
            cmd[j++]=instr[i]; 
	}
    cmd[j]=0;

    return(cmd);
}
#ifdef JAVASCRIPT

static void
js_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
{
	char	line[64];
	char	file[MAX_PATH+1];
	char*	warning;

	if(report==NULL) {
		lprintf(LOG_ERR,"!JavaScript: %s", message);
		return;
    }

	if(report->filename)
		sprintf(file," %s",report->filename);
	else
		file[0]=0;

	if(report->lineno)
		sprintf(line," line %u",report->lineno);
	else
		line[0]=0;

	if(JSREPORT_IS_WARNING(report->flags)) {
		if(JSREPORT_IS_STRICT(report->flags))
			warning="strict warning";
		else
			warning="warning";
	} else
		warning="";

	lprintf(LOG_ERR,"!JavaScript %s%s%s: %s",warning,file,line,message);
}


static BOOL
js_mailproc(SOCKET sock, client_t* client, user_t* user
			,char* fname, char* cmdline
			,char* msgtxt_fname, char* rcptlst_fname, char* proc_err_fname)
{
	char*		p;
	char		path[MAX_PATH+1];
	char		arg[MAX_PATH+1];
	BOOL		success=FALSE;
	JSRuntime*	js_runtime=NULL;
	JSContext*	js_cx=NULL;
	JSObject*	js_glob;
	JSObject*	argv;
	jsuint		argc;
	JSScript*	js_script;
	js_branch_t	js_branch;
	jsval		val;
	jsval		rval=JSVAL_VOID;

	do {

		lprintf(LOG_DEBUG,"%04d JavaScript: Creating runtime: %lu bytes\n"
			,sock, startup->js_max_bytes);

		if((js_runtime = JS_NewRuntime(startup->js_max_bytes))==NULL)
			break;

		lprintf(LOG_DEBUG,"%04d JavaScript: Initializing context (stack: %lu bytes)\n"
			,sock, startup->js_cx_stack);

		if((js_cx = JS_NewContext(js_runtime, startup->js_cx_stack))==NULL)
			break;

		JS_SetErrorReporter(js_cx, js_ErrorReporter);

		/* Global Object */
		if((js_glob=js_CreateGlobalObject(js_cx, &scfg, NULL /*js_global_functions*/))==NULL)
			break;

		/* Internal JS Object */
		if(js_CreateInternalJsObject(js_cx, js_glob, &js_branch)==NULL)
			break;

		/* Client Object */
		if(js_CreateClientObject(js_cx, js_glob, "client", client, sock)==NULL)
			break;

		/* System Object */
		if(js_CreateSystemObject(js_cx, js_glob, &scfg, uptime, startup->host_name, SOCKLIB_DESC)==NULL)
			break;

		/* Socket Class */
		if(js_CreateSocketClass(js_cx, js_glob)==NULL)
			break;

		/* MsgBase Class */
		if(js_CreateMsgBaseClass(js_cx, js_glob, &scfg)==NULL)
			break;

		/* File Class */
		if(js_CreateFileClass(js_cx, js_glob)==NULL)
			break;

		/* User class */
		if(js_CreateUserClass(js_cx, js_glob, &scfg)==NULL) 
			break;

		/* Area and "user" Objects */
		if(!js_CreateUserObjects(js_cx, js_glob, &scfg, user, NULL, NULL)) 
			break;

		/* Convert command-line to argv/argc */
		argv=JS_NewArrayObject(js_cx, 0, NULL);
		JS_DefineProperty(js_cx, js_glob, "argv", OBJECT_TO_JSVAL(argv)
			,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE);

		p=cmdline;
		FIND_WHITESPACE(p); 
		SKIP_WHITESPACE(p);
		for(argc=0;*p;argc++) {
			SAFECOPY(arg,p);
			truncstr(arg," \t");
			val=STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx,arg));
			if(!JS_SetElement(js_cx, argv, argc, &val))
				break;
			FIND_WHITESPACE(p);
			SKIP_WHITESPACE(p);
		}
		JS_DefineProperty(js_cx, js_glob, "argc", INT_TO_JSVAL(argc)
			,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE);

		/* Mailproc "API" filenames */
		JS_DefineProperty(js_cx, js_glob, "message_text_filename"
			,STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx,msgtxt_fname))
			,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);

		JS_DefineProperty(js_cx, js_glob, "recipient_list_filename"
			,STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx,rcptlst_fname))
			,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);

		JS_DefineProperty(js_cx, js_glob, "processing_error_filename"
			,STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx,proc_err_fname))
			,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);

		if(getfext(fname)==NULL) /* No extension specified, assume '.js' */
			strcat(fname,".js");

		SAFECOPY(path,fname);
		if(getfname(path)==path) /* No path specified, assume exec_dir */
			sprintf(path,"%s%s",scfg.exec_dir,fname);

		if((js_script=JS_CompileFile(js_cx, js_glob, path))==NULL)
			break;

		success=JS_ExecuteScript(js_cx, js_glob, js_script, &rval);

	} while(0);

	if(js_cx!=NULL)
		JS_DestroyContext(js_cx);
	if(js_runtime!=NULL)
		JS_DestroyRuntime(js_runtime);

	return(success);
}
#endif
static int parse_header_field(char* buf, smbmsg_t* msg, ushort* type)
	if(buf[0]<=' ' && *type!=UNKNOWN) {	/* folded header, append to previous */
		p=buf;
		truncsp(p);
		smb_hfield_append_str(msg,*type,"\r\n");
		return smb_hfield_append_str(msg, *type, p);
		return smb_hfield_str(msg, *type=RFC822TO, p);
	}
	if(!strnicmp(buf, "REPLY-TO:",9)) {
		p=buf+9;
		smb_hfield_str(msg, *type=RFC822REPLYTO, p);
		if(*p=='<')  {
			p++;
			truncstr(p,">");
		}
		nettype=NET_INTERNET;
		smb_hfield(msg, REPLYTONETTYPE, sizeof(nettype), &nettype);
		return smb_hfield_str(msg, *type=REPLYTONETADDR, p);
		return smb_hfield_str(msg, *type=RFC822FROM, p);
	}
	if(!strnicmp(buf, "ORGANIZATION:",13)) {
		p=buf+13;
		return smb_hfield_str(msg, *type=SENDERORG, p);
	}
	if(!strnicmp(buf, "DATE:",5)) {
		p=buf+5;
		msg->hdr.when_written=rfc822date(p);
	}
	if(!strnicmp(buf, "MESSAGE-ID:",11)) {
		p=buf+11;
		return smb_hfield_str(msg, *type=RFC822MSGID, p);
	}
	if(!strnicmp(buf, "IN-REPLY-TO:",12)) {
		p=buf+12;
		return smb_hfield_str(msg, *type=RFC822REPLYID, p);
	return smb_hfield_str(msg, *type=RFC822HEADER, buf);
static int chk_received_hdr(SOCKET socket,const char *buf,IN_ADDR *dnsbl_result, char *dnsbl, char *dnsbl_ip)
{
	char		host_name[128];
	IN_ADDR		check_addr;
	char		*fromstr;
	char		ip[16];
	char		*p;
	char		*p2;

	fromstr=(char *)MALLOC(strlen(buf)+1);
	if(fromstr==NULL)
		return(0);
	strcpy(fromstr,buf);
	strlwr(fromstr);
	do {
		p=strstr(fromstr,"from ");
		if(p==NULL)
			break;
		p+=4;
			break;
		p2=host_name;
		for(;*p && !isspace(*p) && p2<host_name+126;p++)  {
			*p2++=*p;
		}
		*p2=0;
		p=strtok(fromstr,"[");
		if(p==NULL)
			break;
		p=strtok(NULL,"]");
		if(p==NULL)
			break;
		strncpy(ip,p,16);
		ip[15]=0;
		check_addr.s_addr = inet_addr(ip);
		if(startup->options&MAIL_OPT_DNSBL_DEBUG)
			lprintf(LOG_DEBUG,"%04d DEBUG checking %s (%s)",socket,host_name,ip);
rswindell's avatar
rswindell committed
		if((dnsbl_result->s_addr=dns_blacklisted(socket,check_addr,host_name,dnsbl,dnsbl_ip))!=0)
				lprintf(LOG_WARNING,"%04d !SMTP BLACKLISTED SERVER on %s: %s [%s] = %s"
					,socket, dnsbl, host_name, ip, inet_ntoa(*dnsbl_result));
	} while(0);
	free(fromstr);
	return(dnsbl_result->s_addr);
}

static void smtp_thread(void* arg)
{
	int			rd;
	char		str[512];
	char		value[INI_MAX_VALUE_LEN];
	char**		sec_list;
	char*		section;
	char		buf[1024],*p,*tp,*cp;
	char		hdrfield[512];
	char		alias_buf[128];
rswindell's avatar
rswindell committed
	char		name_alias_buf[128];
	char		reverse_path[128];
	char		date[64];
	char		rcpt_name[128];
	char		rcpt_addr[128];
	char		hello_name[128];
	char		user_name[LEN_ALIAS+1];
	char		user_pass[LEN_PASS+1];
	char		relay_list[MAX_PATH+1];
	char		domain_list[MAX_PATH+1];
	char		spam_bait[MAX_PATH+1];
	char		host_name[128];
	char		host_ip[64];
	char		challenge[256];
	char		response[128];
	char		secret[64];
	char		md5_data[384];
	char		digest[MD5_DIGEST_SIZE];
	char		dest_host[128];
	ushort		dest_port;
	socklen_t	addr_len;
	BOOL		esmtp=FALSE;
	BOOL		forward=FALSE;
	BOOL		no_forward=FALSE;
	BOOL		routed=FALSE;
	BOOL		dnsbl_recvhdr;
	FILE*		msgtxt=NULL;
	FILE*		rcptlst;
	FILE*		proc_cfg;
	FILE*		proc_err;
	char		proc_err_fname[MAX_PATH+1];
	FILE*		spy=NULL;
	SOCKET		socket;
	HOSTENT*	host;
	smb_t		smb;
	smbmsg_t	msg;
	smbmsg_t	newmsg;
	user_t		user;
	client_t	client;
	smtp_t		smtp=*(smtp_t*)arg;
	SOCKADDR_IN server_addr;
	IN_ADDR		dnsbl_result;
	enum {
			 SMTP_STATE_INITIAL
			,SMTP_STATE_HELO
rswindell's avatar
rswindell committed
			,SMTP_STATE_MAIL_FROM
			,SMTP_STATE_RCPT_TO
			,SMTP_STATE_DATA_HEADER
			,SMTP_STATE_DATA_BODY

	} state = SMTP_STATE_INITIAL;

rswindell's avatar
rswindell committed
	enum {
			 SMTP_CMD_NONE
			,SMTP_CMD_MAIL
			,SMTP_CMD_SEND
			,SMTP_CMD_SOML
			,SMTP_CMD_SAML

	} cmd = SMTP_CMD_NONE;

	lprintf(LOG_DEBUG,"%04d SMTP RX Session thread started", socket);
#ifdef _WIN32
	if(startup->inbound_sound[0] && !(startup->options&MAIL_OPT_MUTE)) 
		PlaySound(startup->inbound_sound, NULL, SND_ASYNC|SND_FILENAME);

	addr_len=sizeof(server_addr);
	if((i=getsockname(socket, (struct sockaddr *)&server_addr,&addr_len))!=0) {
		lprintf(LOG_ERR,"%04d !SMTP ERROR %d (%d) getting address/port"
			,socket, i, ERROR_VALUE);
		mail_close_socket(socket);
		thread_down();
	memset(&smb,0,sizeof(smb));
	memset(&msg,0,sizeof(msg));
	memset(&user,0,sizeof(user));
	memset(&relay_user,0,sizeof(relay_user));
	SAFECOPY(host_ip,inet_ntoa(smtp.client_addr.sin_addr));
	lprintf(LOG_INFO,"%04d SMTP Connection accepted from: %s port %u"
		, socket, host_ip, ntohs(smtp.client_addr.sin_port));

	if(startup->options&MAIL_OPT_NO_HOST_LOOKUP)
		host=NULL;
	else
		host=gethostbyaddr ((char *)&smtp.client_addr.sin_addr
			,sizeof(smtp.client_addr.sin_addr),AF_INET);

	if(host!=NULL && host->h_name!=NULL)
		SAFECOPY(host_name,host->h_name);
	else
		strcpy(host_name,"<no name>");

	if(!(startup->options&MAIL_OPT_NO_HOST_LOOKUP)) {
		lprintf(LOG_INFO,"%04d SMTP Hostname: %s", socket, host_name);
		for(i=0;host!=NULL && host->h_aliases!=NULL && host->h_aliases[i]!=NULL;i++)
			lprintf(LOG_INFO,"%04d SMTP HostAlias: %s", socket, host->h_aliases[i]);
#if 0
		if(host!=NULL) {
			ip=resolve_ip(host_name);
			if(ip!=smtp.client_addr.sin_addr.s_addr) {
				smtp.client_addr.sin_addr.s_addr=ip;
				lprintf(LOG_WARNING,"%04d !SMTP DNS/IP ADDRESS MISMATCH: %s vs %s"
					,socket, inet_ntoa(smtp.client_addr.sin_addr), host_ip);
				sockprintf(socket,"550 DNS and IP address mismatch");
				mail_close_socket(socket);
				thread_down();
				return;
			}
		}
#endif
	sprintf(spam_bait,"%sspambait.cfg",scfg.ctrl_dir);
	sprintf(spam_block,"%sspamblock.cfg",scfg.ctrl_dir);

	if(trashcan(&scfg,host_ip,"ip") || findstr(host_ip,spam_block)) {
		lprintf(LOG_NOTICE,"%04d !SMTP BLOCKED SERVER IP ADDRESS: %s"
		sockprintf(socket,"550 Access denied.");
	if(trashcan(&scfg,host_name,"host") || findstr(host_name,spam_block)) {
		lprintf(LOG_NOTICE,"%04d !SMTP BLOCKED SERVER HOSTNAME: %s"
		sockprintf(socket,"550 Access denied.");
	active_clients++, update_clients();
	/*  SPAM Filters (mail-abuse.org) */
	dnsbl_result.s_addr = dns_blacklisted(socket,smtp.client_addr.sin_addr,host_name,dnsbl,dnsbl_ip);
	if(dnsbl_result.s_addr) {
		lprintf(LOG_WARNING,"%04d !SMTP BLACKLISTED SERVER on %s: %s [%s] = %s"
			,socket, dnsbl, host_name, dnsbl_ip, inet_ntoa(dnsbl_result));
		if(startup->options&MAIL_OPT_DNSBL_REFUSE) {
			sprintf(str,"Listed on %s as %s", dnsbl, inet_ntoa(dnsbl_result));
			spamlog(&scfg, "SMTP", "SESSION REFUSED", str, host_name, dnsbl_ip, NULL, NULL);
			sockprintf(socket
				,"550 Mail from %s refused due to listing at %s"
			mail_close_socket(socket);
			lprintf(LOG_WARNING,"%04d !SMTP REFUSED SESSION from blacklisted server"
			if(active_clients)
				active_clients--, update_clients();
	sprintf(smb.file,"%smail",scfg.data_dir);
	if(smb_islocked(&smb)) {
		lprintf(LOG_WARNING,"%04d !SMTP MAIL BASE LOCKED: %s"
			,socket, smb.last_error);
		sockprintf(socket,sys_unavail);
		mail_close_socket(socket);
		thread_down();
		if(active_clients)
			active_clients--, update_clients();
		return;
	}

	srand(time(NULL));	/* seed random number generator */
	rand();	/* throw-away first result */
	sprintf(session_id,"%x%x%lx",socket,rand(),clock());

	sprintf(rcptlst_fname,"%sSMTP.%s.lst", scfg.data_dir, session_id);
	rcptlst=fopen(rcptlst_fname,"w+");
	if(rcptlst==NULL) {
		lprintf(LOG_ERR,"%04d !SMTP ERROR %d creating recipient list: %s"
			,socket, errno, rcptlst_fname);
		thread_down();
		if(active_clients)
			active_clients--, update_clients();
	if(trashcan(&scfg,host_name,"smtpspy") 
		|| trashcan(&scfg,host_ip,"smtpspy")) {
		sprintf(str,"%sSMTPSPY.TXT", scfg.data_dir);
		spy=fopen(str,"a");
	}

	/* Initialize client display */
	client.size=sizeof(client);
	client.time=time(NULL);
	SAFECOPY(client.addr,host_ip);
	SAFECOPY(client.host,host_name);
	client.port=ntohs(smtp.client_addr.sin_port);
	client.protocol="SMTP";
	client.user="<unknown>";
	client_on(socket,&client,FALSE /* update */);

	sprintf(str,"SMTP: %s",host_ip);
	status(str);

	sockprintf(socket,"220 %s Synchronet SMTP Server %s-%s Ready"
		,startup->host_name,revision,PLATFORM_DESC);
	while(1) {
		rd = sockreadline(socket, buf, sizeof(buf));
		if(spy!=NULL)
			fprintf(spy,"%s\n",buf);
		if(state>=SMTP_STATE_DATA_HEADER) {
			if(!strcmp(buf,".")) {

				state=SMTP_STATE_HELO;	/* RESET state machine here in case of error */
rswindell's avatar
rswindell committed
				cmd=SMTP_CMD_NONE;
					lprintf(LOG_ERR,"%04d !SMTP NO MESSAGE TEXT FILE POINTER?", socket);
					sockprintf(socket,"554 No message text");
					continue;
				}

				if(ftell(msgtxt)<1) {
					lprintf(LOG_ERR,"%04d !SMTP INVALID MESSAGE LENGTH: %ld (%lu lines)"
						, socket, ftell(msgtxt), lines);
					sockprintf(socket,"554 No message text");
				lprintf(LOG_INFO,"%04d SMTP End of message (body: %lu lines, %lu bytes, header: %lu lines, %lu bytes)"
					, socket, lines, ftell(msgtxt)-hdr_len, hdr_lines, hdr_len);

				if(telegram==TRUE) {		/* Telegram */
					const char* head="\1n\1h\1cInstant Message\1n from \1h\1y";
					const char* tail="\1n:\r\n\1h";
					rewind(msgtxt);
					length=filelength(fileno(msgtxt));
					
					p=strchr(sender_addr,'@');
					if(p==NULL || resolve_ip(p+1)!=smtp.client_addr.sin_addr.s_addr) 
						/* Append real IP and hostname if different */
						sprintf(str,"%s%s\r\n\1w[\1n%s\1h] (\1n%s\1h)%s"
							,head,sender_addr,host_ip,host_name,tail);
					else
						sprintf(str,"%s%s%s",head,sender_addr,tail);
					
					if((telegram_buf=(char*)malloc(length+strlen(str)+1))==NULL) {
						lprintf(LOG_CRIT,"%04d !SMTP ERROR allocating %lu bytes of memory for telegram from %s"
							,socket,length+strlen(str)+1,sender_addr);
						sockprintf(socket, "452 Insufficient system storage");
						continue; 
					}
					strcpy(telegram_buf,str);	/* can't use SAFECOPY here */
					if(fread(telegram_buf+strlen(str),1,length,msgtxt)!=length) {
						lprintf(LOG_ERR,"%04d !SMTP ERROR reading %lu bytes from telegram file"
							,socket,length);
						sockprintf(socket, "452 Insufficient system storage");
						free(telegram_buf);
						continue; 
					}
					telegram_buf[length+strlen(str)]=0;	/* Need ASCIIZ */

					/* Send telegram to users */
					rcpt_count=0;
					while(!feof(rcptlst)  && rcpt_count<startup->max_recipients) {
						if(fgets(str,sizeof(str),rcptlst)==NULL)
							break;
						usernum=atoi(str);
						if(fgets(rcpt_name,sizeof(rcpt_name),rcptlst)==NULL)
							break;
						truncsp(rcpt_name);
						if(fgets(rcpt_addr,sizeof(rcpt_addr),rcptlst)==NULL)
							break;
						truncsp(rcpt_addr);
						putsmsg(&scfg,usernum,telegram_buf);
						lprintf(LOG_INFO,"%04d SMTP Created telegram (%ld/%u bytes) from %s to %s <%s>"
							,socket, length, strlen(telegram_buf), sender_addr, rcpt_name, rcpt_addr);
						rcpt_count++;
					}
					free(telegram_buf);
					sockprintf(socket,ok_rsp);
					telegram=FALSE;
					continue;
				}

				fclose(msgtxt), msgtxt=NULL;
				fclose(rcptlst), rcptlst=NULL;
				if(startup->proc_cfg_file[0] 
					&& (proc_cfg=fopen(startup->proc_cfg_file,"r"))!=NULL) {
					sprintf(proc_err_fname,"%sSMTP.%s.err", scfg.data_dir, session_id);
					remove(proc_err_fname);

					while(!feof(proc_cfg)) {
						if(!fgets(tmp,sizeof(tmp),proc_cfg))
							break;
						truncsp(tmp);
						p=tmp;
						if(*p==';' || *p==0)	/* comment or blank line */
							continue;
						mailcmdstr(p, msgtxt_fname, rcptlst_fname, proc_err_fname
							,host_name, host_ip, relay_user.number, str);
						lprintf(LOG_DEBUG,"%04d SMTP Executing external process: %s", socket, str);
#ifdef JAVASCRIPT
						if(*p=='?') {
							/* JavaScript */
							SAFECOPY(fname,str+1);
							truncstr(fname," \t");
							js_mailproc(socket, &client, &relay_user
								,fname, p ,msgtxt_fname, rcptlst_fname, proc_err_fname);
						} else									
#endif
							/* Native */
							if((i=system(str))!=0)
								lprintf(LOG_WARNING,"%04d !SMTP system(%s) returned %d (errno: %d)"
									,socket, str, i, errno);