Newer
Older
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_scope, "argc", INT_TO_JSVAL(argc)
,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE);
lprintf(LOG_DEBUG,"%04d %s Evaluating: %s"
,sock, log_prefix, mailproc->eval);
js_script=JS_CompileScript(*js_cx, js_scope, mailproc->eval, strlen(mailproc->eval), NULL, 1);
} else {
lprintf(LOG_DEBUG,"%04d %s Executing: %s"
if((js_script=JS_CompileFile(*js_cx, js_scope, path)) != NULL)
js_PrepareToExecute(*js_cx, js_scope, path, /* startup_dir: */NULL, js_scope);
/* ToDo: Set operational callback */
success=JS_ExecuteScript(*js_cx, js_scope, js_script, &rval);
JS_GetProperty(*js_cx, js_scope, "exit_code", &rval);
if(rval!=JSVAL_VOID && JSVAL_IS_NUMBER(rval))
JS_ValueToInt32(*js_cx,rval,result);
js_EvalOnExit(*js_cx, js_scope, &js_callback);
JS_ReportPendingException(*js_cx);
} while(0);
JS_ENDREQUEST(*js_cx);
return(success);
}
void js_cleanup(JSRuntime* js_runtime, JSContext* js_cx, JSObject** js_glob)
if(js_cx!=NULL) {
JS_BEGINREQUEST(js_cx);
JS_RemoveObjectRoot(js_cx, js_glob);
JS_ENDREQUEST(js_cx);
}
if(js_runtime!=NULL)
jsrt_Release(js_runtime);
}
static char* get_header_field(char* buf, char* name, size_t maxlen)
{
size_t len;
if(buf[0]<=' ') /* folded header */
return NULL;
if((p=strchr(buf,':'))==NULL)
return NULL;
len = p-buf;
if(len >= maxlen)
len = maxlen-1;
truncsp(name);
p++; /* skip colon */
SKIP_WHITESPACE(p);
return p;
}
static int parse_header_field(char* buf, smbmsg_t* msg, ushort* type)
{
char* p;
char* tp;
char field[128];
int len;
ushort nettype;
if(buf[0]<=' ' && *type!=UNKNOWN) { /* folded header, append to previous */
p=buf;
truncsp(p);
if(*type==RFC822HEADER || *type==SMTPRECEIVED)
smb_hfield_append_str(msg,*type,"\r\n");
else { /* Unfold other common header field types (e.g. Subject, From, To) */
smb_hfield_append_str(msg,*type," ");
SKIP_WHITESPACE(p);
}
return smb_hfield_append_str(msg, *type, p);
}
if((p=strchr(buf,':'))==NULL)
return smb_hfield_str(msg, *type=RFC822HEADER, buf);
len=(ulong)p-(ulong)buf;
if(len>sizeof(field)-1)
len=sizeof(field)-1;
sprintf(field,"%.*s",len,buf);
truncsp(field);
p++; /* skip colon */
SKIP_WHITESPACE(p);
truncsp(p);
if(!stricmp(field, "TO"))
return smb_hfield_str(msg, *type=RFC822TO, p);
if(!stricmp(field, "REPLY-TO")) {
smb_hfield_str(msg, *type=RFC822REPLYTO, p);
if((tp=strrchr(p,'<'))!=NULL) {
tp++;
truncstr(tp,">");
p=tp;
}
nettype=NET_INTERNET;
smb_hfield(msg, REPLYTONETTYPE, sizeof(nettype), &nettype);
return smb_hfield_str(msg, *type=REPLYTONETADDR, p);
}
if(!stricmp(field, "FROM"))
return smb_hfield_str(msg, *type=RFC822FROM, p);
if(!stricmp(field, "ORGANIZATION"))
return smb_hfield_str(msg, *type=SENDERORG, p);
if(!stricmp(field, "DATE")) {
msg->hdr.when_written=rfc822date(p);
*type=UNKNOWN;
return SMB_SUCCESS;
}
if(!stricmp(field, "MESSAGE-ID"))
return smb_hfield_str(msg, *type=RFC822MSGID, p);
if(!stricmp(field, "IN-REPLY-TO"))
return smb_hfield_str(msg, *type=RFC822REPLYID, p);
if(!stricmp(field, "CC"))
return smb_hfield_str(msg, *type=SMB_CARBONCOPY, p);
if(!stricmp(field, "RECEIVED"))
return smb_hfield_str(msg, *type=SMTPRECEIVED, p);
if(!stricmp(field, "RETURN-PATH")) {
*type=UNKNOWN;
return SMB_SUCCESS; /* Ignore existing "Return-Path" header fields */
}
/* Fall-through */
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];
char *fromstr;
char ip[16];
char *p;
char *p2;
if(fromstr==NULL)
return(0);
strlwr(fromstr);
do {
p=strstr(fromstr,"from ");
if(p==NULL)
break;
p+=4;
SKIP_WHITESPACE(p);
if(*p==0)
break;
p2=host_name;
for(;*p && !isspace((unsigned char)*p) && p2<host_name+126;p++) {
*p2++=*p;
}
*p2=0;
p=strtok_r(fromstr,"[",&last);
if(p==NULL)
break;
p=strtok_r(NULL,"]",&last);
if(p==NULL)
break;
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
if(strnicmp("IPv6:", p, 5)) {
p+=5;
SKIP_WHITESPACE(p);
memset(&ai, 0, sizeof(ai));
ai.ai_flags = AI_NUMERICHOST|AI_NUMERICSERV|AI_PASSIVE;
if(getaddrinfo(p, NULL, &ai, &res)!=0)
break;
if(res->ai_family == AF_INET6)
memcpy(&addr, res->ai_addr, res->ai_addrlen);
else
break;
freeaddrinfo(res);
}
else {
strncpy(ip,p,16);
ip[15]=0;
addr.in.sin_family=AF_INET;
addr.in.sin_addr.s_addr=inet_addr(ip);
lprintf(LOG_DEBUG,"%04d SMTP DNSBL checking received header address %s [%s]",socket,host_name,ip);
}
if((dnsbl_result->s_addr=dns_blacklisted(socket,&addr,host_name,dnsbl,dnsbl_ip))!=0)
lprintf(LOG_NOTICE,"%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 strip_char(char* str, char ch)
{
char* src;
char* p;
char* tmp = strdup(str);
if(tmp == NULL)
return;
p=tmp;
for(src = str; *src; src++) {
if(*src != ch)
*(p++) = *src;
}
*p=0;
strcpy(str, tmp);
free(tmp);
}
static void parse_mail_address(char* p
,char* name, size_t name_len
,char* addr, size_t addr_len)
{
char* tp;
char tmp[128];
SKIP_WHITESPACE(p);
/* Get the address */
if((tp=strrchr(p,'<'))!=NULL)
tp++;
else
tp=p;
SKIP_WHITESPACE(tp);
truncstr(addr,">( ");
SAFECOPY(tmp,p);
p=tmp;
/* Get the "name" (if possible) */
if((tp=strchr(p,'"'))!=NULL) { /* name in quotes? */
p=tp+1;
tp=strrchr(p,'"');
} else if((tp=strchr(p,'('))!=NULL) { /* name in parenthesis? */
p=tp+1;
} else if(*p=='<') { /* address in brackets? */
p++;
} else /* name, then address in brackets */
tp=strchr(p,'<');
if(tp) *tp=0;
truncsp(name);
}
/* Decode quoted-printable content-transfer-encoded text */
/* Ignores (strips) unsupported ctrl chars and non-ASCII chars */
/* Does not enforce 76 char line length limit */
static char* qp_decode(char* buf)
{
uchar* p=(uchar*)buf;
uchar* dest=p;
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
for(;;p++) {
if(*p==0) {
*dest++='\r';
*dest++='\n';
break;
}
if(*p==' ' || (*p>='!' && *p<='~' && *p!='=') || *p=='\t')
*dest++=*p;
else if(*p=='=') {
p++;
if(*p==0) /* soft link break */
break;
if(isxdigit(*p) && isxdigit(*(p+1))) {
char hex[3];
hex[0]=*p;
hex[1]=*(p+1);
hex[2]=0;
/* ToDo: what about encoded NULs and the like? */
*dest++=(uchar)strtoul(hex,NULL,16);
p++;
} else { /* bad encoding */
*dest++='=';
*dest++=*p;
}
}
}
*dest=0;
return buf;
}
static BOOL checktag(scfg_t *scfg, char *tag, uint usernum)
{
char fname[MAX_PATH+1];
if(tag==NULL)
return(FALSE);
SAFEPRINTF2(fname,"%suser/%04d.smtpblock",scfg->data_dir,usernum);
return(findstr(tag, fname));
}
static BOOL smtp_splittag(char *in, char **name, char **tag)
{
char *last;
if(in==NULL)
return(FALSE);
*name=strtok_r(in, "#", &last);
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
if(*name) {
*tag=strtok_r(NULL, "", &last);
return(TRUE);
}
return(FALSE);
}
static uint smtp_matchuser(scfg_t *scfg, char *str, BOOL aliases, BOOL datdupe)
{
char *user=strdup(str);
char *name;
char *tag=NULL;
uint usernum=0;
if(!user)
return(0);
if(!smtp_splittag(user, &name, &tag))
goto end;
if(datdupe)
usernum=userdatdupe(scfg, 0, U_NAME, LEN_NAME, name, /* del */FALSE, /* next */FALSE);
else
usernum=matchuser(scfg, name, aliases);
if(!usernum)
goto end;
if(checktag(scfg, tag, usernum))
usernum=UINT_MAX;
end:
free(user);
return(usernum);
}
static void smtp_thread(void* arg)
{
int i,j;
char path[MAX_PATH+1];
char value[INI_MAX_VALUE_LEN];
str_list_t sec_list;
char* section;
char buf[1024],*p,*tp,*cp;
char hdrfield[512];
char alias_buf[128];
char reverse_path[128];
char date[64];
char qwkid[32];
char rcpt_to[128];
char rcpt_name[128];
char rcpt_addr[128];

rswindell
committed
char sender[128];
char sender_ext[128];

rswindell
committed
char sender_addr[128];
char user_name[128];
char user_pass[128];
char relay_list[MAX_PATH+1];
char domain_list[MAX_PATH+1];
char spam_bait[MAX_PATH+1];
char spam_block[MAX_PATH+1];
char spam_block_exemptions[MAX_PATH+1];
BOOL spam_block_exempt=FALSE;
char host_ip[INET6_ADDRSTRLEN];
char server_ip[INET6_ADDRSTRLEN];

rswindell
committed
char* telegram_buf;
char* msgbuf;
char challenge[256];
char response[128];
char secret[64];
char md5_data[384];
uchar digest[MD5_DIGEST_SIZE];
char dest_host[128];
char* errmsg;
ushort dest_port;
ushort hfield_type;
ushort agent;
ulong hdr_lines=0;
ulong hdr_len=0;
ulong badcmds=0;

rswindell
committed
BOOL telegram=FALSE;
BOOL forward=FALSE;
BOOL no_forward=FALSE;
BOOL auth_login;
BOOL routed=FALSE;
BOOL dnsbl_recvhdr;
BOOL msg_handled;
uint subnum=INVALID_SUB;
char msgtxt_fname[MAX_PATH+1];
char newtxt_fname[MAX_PATH+1];
char logtxt_fname[MAX_PATH+1];
char rcptlst_fname[MAX_PATH+1];
ushort rcpt_count=0;
FILE* proc_err;
char proc_err_fname[MAX_PATH+1];
char session_id[MAX_PATH+1];
FILE* spy=NULL;
SOCKET socket;
int smb_error;
smbmsg_t msg;
smbmsg_t newmsg;
user_t user;
user_t relay_user;

rswindell
committed
node_t node;
client_t client;
smtp_t smtp=*(smtp_t*)arg;
IN_ADDR dnsbl_result;
int mailproc_match;
JSRuntime* js_runtime=NULL;
JSContext* js_cx=NULL;
JSObject* js_glob=NULL;
struct mailproc* mailproc;
enum {
SMTP_STATE_INITIAL
,SMTP_STATE_HELO
,SMTP_STATE_DATA_HEADER
,SMTP_STATE_DATA_BODY
} state = SMTP_STATE_INITIAL;
enum {
SMTP_CMD_NONE
,SMTP_CMD_MAIL
,SMTP_CMD_SEND
,SMTP_CMD_SOML
,SMTP_CMD_SAML
} cmd = SMTP_CMD_NONE;
enum {
ENCODING_NONE
,ENCODING_BASE64
,ENCODING_QUOTED_PRINTABLE
} content_encoding = ENCODING_NONE;
SetThreadName("sbbs/SMTP");
thread_up(TRUE /* setuid */);
free(arg);
socket=smtp.socket;
lprintf(LOG_DEBUG,"%04d SMTP Session thread started", socket);
if(startup->inbound_sound[0] && !(startup->options&MAIL_OPT_MUTE))
PlaySound(startup->inbound_sound, NULL, SND_ASYNC|SND_FILENAME);
addr_len=sizeof(server_addr);
lprintf(LOG_CRIT,"%04d !SMTP ERROR %d (%d) getting address/port"
sockprintf(socket,sys_error);
mail_close_socket(socket);
thread_down();
if((mailproc_to_match=malloc(sizeof(BOOL)*mailproc_count))==NULL) {
lprintf(LOG_CRIT,"%04d !SMTP ERROR allocating memory for mailproc_to_match", socket);
sockprintf(socket,sys_error);
mail_close_socket(socket);
thread_down();
return;
}
memset(mailproc_to_match,FALSE,sizeof(BOOL)*mailproc_count);
memset(&smb,0,sizeof(smb));

rswindell
committed
memset(&msg,0,sizeof(msg));

rswindell
committed
memset(&user,0,sizeof(user));
memset(&relay_user,0,sizeof(relay_user));
lprintf(LOG_INFO,"%04d SMTP Connection accepted on port %u from: %s port %u"
,socket, inet_addrport(&server_addr), host_ip, inet_addrport(&smtp.client_addr));
if(getnameinfo(&smtp.client_addr.addr, smtp.client_addr_len, host_name, sizeof(host_name), NULL, 0, (startup->options&MAIL_OPT_NO_HOST_LOOKUP)?NI_NUMERICHOST:0)!=0)
SAFECOPY(host_name, "<no name>");
if(!(startup->options&MAIL_OPT_NO_HOST_LOOKUP))
lprintf(LOG_INFO,"%04d SMTP Hostname: %s", socket, host_name);
protected_uint32_adjust(&active_clients, 1);
update_clients();
SAFECOPY(hello_name,host_name);
SAFEPRINTF(spam_bait,"%sspambait.cfg",scfg.ctrl_dir);
SAFEPRINTF(spam_block,"%sspamblock.cfg",scfg.ctrl_dir);
SAFEPRINTF(spam_block_exemptions,"%sspamblock_exempt.cfg",scfg.ctrl_dir);
inet_addrtop(&server_addr,server_ip,sizeof(server_ip));
if(strcmp(server_ip, host_ip)==0) {
/* local connection */
dnsbl_result.s_addr=0;
} else {
ulong banned = loginBanned(&scfg, startup->login_attempt_list, socket, host_name, startup->login_attempt, &attempted);
char ban_duration[128];
lprintf(LOG_NOTICE, "%04d !TEMPORARY BAN of %s (%u login attempts, last: %s) - remaining: %s"
,socket, host_ip, attempted.count, attempted.user, seconds_to_str(banned, ban_duration));
mail_close_socket(socket);
thread_down();
protected_uint32_adjust(&active_clients, -1);
update_clients();
free(mailproc_to_match);
return;
}
spam_block_exempt = findstr(host_ip,spam_block_exemptions) || findstr(host_name,spam_block_exemptions);
if(trashcan(&scfg,host_ip,"ip")
|| (findstr(host_ip,spam_block) && !spam_block_exempt)) {
lprintf(LOG_NOTICE,"%04d !SMTP CLIENT IP ADDRESS BLOCKED: %s (%u total)"
,socket, host_ip, ++stats.sessions_refused);
sockprintf(socket,"550 CLIENT IP ADDRESS BLOCKED: %s", host_ip);
mail_close_socket(socket);
thread_down();
protected_uint32_adjust(&active_clients, -1);
update_clients();
return;
}
if(trashcan(&scfg,host_name,"host")
|| (findstr(host_name,spam_block) && !spam_block_exempt)) {
lprintf(LOG_NOTICE,"%04d !SMTP CLIENT HOSTNAME BLOCKED: %s (%u total)"
,socket, host_name, ++stats.sessions_refused);
sockprintf(socket,"550 CLIENT HOSTNAME BLOCKED: %s", host_name);
mail_close_socket(socket);
thread_down();
protected_uint32_adjust(&active_clients, -1);
update_clients();
/* SPAM Filters (mail-abuse.org) */
dnsbl_result.s_addr = dns_blacklisted(socket,&smtp.client_addr,host_name,dnsbl,dnsbl_ip);
if(dnsbl_result.s_addr) {
lprintf(LOG_NOTICE,"%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) {
SAFEPRINTF2(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"
,dnsbl_ip, dnsbl);
mail_close_socket(socket);
lprintf(LOG_NOTICE,"%04d !SMTP REFUSED SESSION from blacklisted server (%u total)"
,socket, ++stats.sessions_refused);
thread_down();
protected_uint32_adjust(&active_clients, -1);
update_clients();
return;
}
}
SAFEPRINTF(smb.file,"%smail",scfg.data_dir);
if(smb_islocked(&smb)) {
lprintf(LOG_CRIT,"%04d !SMTP MAIL BASE LOCKED: %s"
,socket, smb.last_error);
sockprintf(socket,sys_unavail);
mail_close_socket(socket);
thread_down();
protected_uint32_adjust(&active_clients, -1);
update_clients();
return;
}
SAFEPRINTF(spam.file,"%sspam",scfg.data_dir);
spam.retry_time=scfg.smb_retry_time;
spam.subnum=INVALID_SUB;
srand((unsigned int)(time(NULL) ^ (time_t)GetCurrentThreadId())); /* seed random number generator */
rand(); /* throw-away first result */
SAFEPRINTF4(session_id,"%x%x%x%lx",getpid(),socket,rand(),clock());
lprintf(LOG_DEBUG,"%04d SMTP Session ID=%s", socket, session_id);
SAFEPRINTF2(msgtxt_fname,"%sSBBS_SMTP.%s.msg", scfg.temp_dir, session_id);
SAFEPRINTF2(newtxt_fname,"%sSBBS_SMTP.%s.new", scfg.temp_dir, session_id);
SAFEPRINTF2(logtxt_fname,"%sSBBS_SMTP.%s.log", scfg.temp_dir, session_id);
SAFEPRINTF2(rcptlst_fname,"%sSBBS_SMTP.%s.lst", scfg.temp_dir, session_id);
rcptlst=fopen(rcptlst_fname,"w+");
if(rcptlst==NULL) {
lprintf(LOG_CRIT,"%04d !SMTP ERROR %d creating recipient list: %s"
,socket, errno, rcptlst_fname);
sockprintf(socket,sys_error);

rswindell
committed
mail_close_socket(socket);
protected_uint32_adjust(&active_clients, -1);
update_clients();
if(trashcan(&scfg,host_name,"smtpspy")
|| trashcan(&scfg,host_ip,"smtpspy")) {
SAFEPRINTF(str,"%ssmtpspy.txt", scfg.logs_dir);
spy=fopen(str,"a");
}
/* Initialize client display */
client.size=sizeof(client);
client.time=time32(NULL);
SAFECOPY(client.addr,host_ip);
SAFECOPY(client.host,host_name);
client.protocol="SMTP";
client.user="<unknown>";
client_on(socket,&client,FALSE /* update */);
SAFEPRINTF(str,"SMTP: %s",host_ip);
&& (login_attempts=loginAttempts(startup->login_attempt_list, &smtp.client_addr)) > 1) {
lprintf(LOG_DEBUG,"%04d SMTP Throttling suspicious connection from: %s (%u login attempts)"
mswait(login_attempts*startup->login_attempt.throttle);
}
/* SMTP session active: */
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(rd<0)
truncsp(buf);
if(spy!=NULL)
fprintf(spy,"%s\n",buf);
if(relay_user.number==0 && dnsbl_result.s_addr && startup->options&MAIL_OPT_DNSBL_THROTTLE)
mswait(DNSBL_THROTTLE_VALUE);
if(state>=SMTP_STATE_DATA_HEADER) {
if(!strcmp(buf,".")) {

rswindell
committed
state=SMTP_STATE_HELO; /* RESET state machine here in case of error */

rswindell
committed
if(msgtxt==NULL) {
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(!socket_check(socket, NULL, NULL, 0)) {
lprintf(LOG_WARNING,"%04d !SMTP sender disconnected (premature evacuation)", socket);
continue;
}
stats.msgs_received++;
/* Twit-listing (sender's name and e-mail addresses) here */
SAFEPRINTF(path,"%stwitlist.cfg",scfg.ctrl_dir);
if(fexist(path) && (findstr(sender,path) || findstr(sender_addr,path))) {
lprintf(LOG_NOTICE,"%04d !SMTP FILTERING TWIT-LISTED SENDER: %s <%s> (%u total)"
,socket, sender, sender_addr, ++stats.msgs_refused);
SAFEPRINTF2(tmp,"Twit-listed sender: %s <%s>", sender, sender_addr);
spamlog(&scfg, "SMTP", "REFUSED", tmp, host_name, host_ip, rcpt_addr, reverse_path);
sockprintf(socket, "554 Sender not allowed.");
continue;
}
if(telegram==TRUE) { /* Telegram */
const char* head="\1n\1h\1cInstant Message\1n from \1h\1y";
const char* tail="\1n:\r\n\1h";
struct addrinfo ai;
struct addrinfo *res,*cur;
BOOL matched=FALSE;
rewind(msgtxt);
length=filelength(fileno(msgtxt));
p=strchr(sender_addr,'@');
memset(&ai, 0, sizeof(ai));
ai.ai_flags = AI_PASSIVE;
ai.ai_family = smtp.client_addr.addr.sa_family;
if(getaddrinfo(p+1, NULL, &ai, &res) != 0)
p=NULL;
else {
for(cur=res; cur; cur=cur->ai_next) {
char cur_ip[INET6_ADDRSTRLEN];
if(inet_addrtop((void *)cur->ai_addr, cur_ip, sizeof(cur_ip))) {
if(strcmp(host_ip, cur_ip)==0)
matched=TRUE;
}
}
freeaddrinfo(res);
if(!matched)
p=NULL;
}
if(p==NULL)
/* Append real IP and hostname if different */
safe_snprintf(str,sizeof(str),"%s%s\r\n\1w[\1n%s\1h] (\1n%s\1h)%s"
,head,sender_addr,host_ip,host_name,tail);
else
safe_snprintf(str,sizeof(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, insuf_stor);
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, insuf_stor);
free(telegram_buf);
continue;
}
telegram_buf[length+strlen(str)]=0; /* Need ASCIIZ */
/* Send telegram to users */
sec_list=iniReadSectionList(rcptlst,NULL); /* Each section is a recipient */
for(rcpt_count=0; sec_list!=NULL
&& sec_list[rcpt_count]!=NULL
&& (startup->max_recipients==0 || rcpt_count<startup->max_recipients); rcpt_count++) {
section=sec_list[rcpt_count];
SAFECOPY(rcpt_to,iniReadString(rcptlst,section ,smb_hfieldtype(RECIPIENT),"unknown",value));
usernum=iniReadInteger(rcptlst,section ,smb_hfieldtype(RECIPIENTEXT),0);
SAFECOPY(rcpt_addr,iniReadString(rcptlst,section ,smb_hfieldtype(RECIPIENTNETADDR),rcpt_to,value));
if((i=putsmsg(&scfg,usernum,telegram_buf))==0)
lprintf(LOG_INFO,"%04d SMTP Created telegram (%ld/%u bytes) from %s to %s <%s>"
,socket, length, strlen(telegram_buf), sender_addr, rcpt_to, rcpt_addr);
else
lprintf(LOG_ERR,"%04d !SMTP ERROR %d creating telegram from %s to %s <%s>"
,socket, i, sender_addr, rcpt_to, rcpt_addr);
}
iniFreeStringList(sec_list);
free(telegram_buf);
sockprintf(socket,ok_rsp);
telegram=FALSE;
continue;
}
fclose(msgtxt), msgtxt=NULL;
fclose(rcptlst), rcptlst=NULL;
/* External Mail Processing here */
mailproc=NULL;
msg_handled=FALSE;
if(mailproc_count) {
SAFEPRINTF2(proc_err_fname,"%sSBBS_SMTP.%s.err", scfg.temp_dir, session_id);
remove(proc_err_fname);
for(i=0;i<mailproc_count && !msg_handled;i++) {
struct mailproc* mp=&mailproc_list[i];
if(mp->disabled)
if(!mp->process_dnsbl && dnsbl_result.s_addr)
continue;
if(!mp->process_spam && spam_bait_result)
continue;
if(!chk_ar(&scfg,mp->ar,&relay_user,&client))
if(mp->to!=NULL && !mailproc_to_match[i])
continue;
if(mp->from!=NULL
&& !findstr_in_list(sender_addr, mp->from))
mailcmdstr(mp->cmdline
,msgtxt_fname, newtxt_fname, logtxt_fname
,rcptlst_fname, proc_err_fname
,host_name, host_ip, relay_user.number
,sender, sender_addr, reverse_path, str);
lprintf(LOG_INFO,"%04d SMTP Executing external mail processor: %s"
,socket, mp->name);
lprintf(LOG_DEBUG,"%04d SMTP Executing external command: %s"
,socket, str);
if((j=system(str))!=0) {
lprintf(LOG_NOTICE,"%04d SMTP system(%s) returned %d (errno: %d)"
,socket, str, j, errno);
if(mp->ignore_on_error) {
lprintf(LOG_WARNING,"%04d !SMTP IGNORED MAIL due to mail processor (%s) error: %d"
,socket, mp->name, j);
msg_handled=TRUE;
}
}
} else { /* JavaScript */
,msgtxt_fname, newtxt_fname, logtxt_fname
,rcpt_addr
,rcptlst_fname, proc_err_fname
,sender, sender_addr, reverse_path, hello_name, &js_result
#if 0 /* calling exit() in a script causes js_mailproc to return FALSE */
lprintf(LOG_NOTICE,"%04d !SMTP JavaScript mailproc command (%s) failed (returned: %d)"
if(mailproc->ignore_on_error) {
lprintf(LOG_WARNING,"%04d !SMTP IGNORED MAIL due to mail processor (%s) failure"
,socket, mailproc->name);
msg_handled=TRUE;
}
#endif
}
}
if(!mp->passthru || flength(proc_err_fname)>0 || !fexist(msgtxt_fname) || !fexist(rcptlst_fname)) {
mailproc=mp;
msg_handled=TRUE;
break;
}
if(flength(proc_err_fname)>0
&& (proc_err=fopen(proc_err_fname,"r"))!=NULL) {
lprintf(LOG_WARNING,"%04d !SMTP External mail processor (%s) created: %s"
,socket, mailproc->name, proc_err_fname);
while(!feof(proc_err)) {
int n;
if(!fgets(str,sizeof(str),proc_err))
break;
truncsp(str);
lprintf(LOG_WARNING,"%04d !SMTP External mail processor (%s) error: %s"
,socket, mailproc->name, str);
n=atoi(str);
if(n>=100 && n<1000)
sockprintf(socket,"%s", str);
else
sockprintf(socket,"554%c%s"
,ftell(proc_err)<filelength(fileno(proc_err)) ? '-' : ' '
,str);
}
fclose(proc_err);
msg_handled=TRUE;
}
else if(!fexist(msgtxt_fname) || !fexist(rcptlst_fname)) {
lprintf(LOG_NOTICE,"%04d SMTP External mail processor (%s) removed %s file"
,socket
,mailproc->name
,fexist(msgtxt_fname)==FALSE ? "message text" : "recipient list");
sockprintf(socket,ok_rsp);
msg_handled=TRUE;
}
else if(msg_handled)
sockprintf(socket,ok_rsp);
remove(proc_err_fname); /* Remove error file here */
}
/* Re-open files */
/* We must do this before continuing for handled msgs */
/* to prevent freopen(NULL) and orphaned temp files */
if((rcptlst=fopen(rcptlst_fname,fexist(rcptlst_fname) ? "r":"w+"))==NULL) {
lprintf(LOG_ERR,"%04d !SMTP ERROR %d re-opening recipient list: %s"
,socket, errno, rcptlst_fname);
if(!msg_handled)
sockprintf(socket,sys_error);
continue;
}
if(!msg_handled && subnum==INVALID_SUB && iniReadSectionCount(rcptlst,NULL) < 1) {
lprintf(LOG_DEBUG,"%04d SMTP No recipients in recipient list file (message handled by external mail processor?)"
,socket);
sockprintf(socket,ok_rsp);
msg_handled=TRUE;
}
if(msg_handled) {
if(mailproc!=NULL)
lprintf(LOG_NOTICE,"%04d SMTP Message handled by external mail processor (%s, %u total)"
,socket, mailproc->name, ++mailproc->handled);
continue;
}
/* If mailproc has written new message text to .new file, use that instead of .msg */
if(flength(newtxt_fname) > 0) {
remove(msgtxt_fname);
SAFECOPY(msgtxt_fname, newtxt_fname);
} else
remove(newtxt_fname);
if((msgtxt=fopen(msgtxt_fname,"rb"))==NULL) {
lprintf(LOG_ERR,"%04d !SMTP ERROR %d re-opening message file: %s"
,socket, errno, msgtxt_fname);
sockprintf(socket,sys_error);
continue;
}
/* Initialize message header */
smb_freemsgmem(&msg);
memset(&msg,0,sizeof(smbmsg_t));
/* Parse message header here */
hfield_type=UNKNOWN;
smb_error=SMB_SUCCESS; /* no SMB error */
errmsg=insuf_stor;
while(!feof(msgtxt)) {
char field[32];
if(!fgets(buf,sizeof(buf),msgtxt))
break;
truncsp(buf);
if(buf[0]==0) /* blank line marks end of header */
break;
if((p=get_header_field(buf, field, sizeof(field)))!=NULL) {
if(stricmp(field, "SUBJECT")==0) {
/* SPAM Filtering/Logging */
if(relay_user.number==0) {
if(trashcan(&scfg,p,"subject")) {
lprintf(LOG_NOTICE,"%04d !SMTP BLOCKED SUBJECT (%s) from: %s (%u total)"
,socket, p, reverse_path, ++stats.msgs_refused);
SAFEPRINTF2(tmp,"Blocked subject (%s) from: %s"
,p, reverse_path);