Newer
Older
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);
if(startup->options&MAIL_OPT_DEBUG_POP3)
lprintf(LOG_INFO,"%04d %s Hostname: %s [%s]", socket, client.protocol, host_name, host_ip);
if (pop3.tls_port) {
if (get_ssl_cert(&scfg, &estr, &level) == -1) {
if (estr) {
lprintf(level, "%04d %s !Failure getting certificate: %s", socket, client.protocol, estr);
free_crypt_attrstr(estr);
mail_close_socket(&socket, &session);
thread_down();
return;
}
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;
}
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;
}
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;
}
nodelay = TRUE;
setsockopt(socket,IPPROTO_TCP,TCP_NODELAY,(char*)&nodelay,sizeof(nodelay));
nb=0;
ioctlsocket(socket,FIONBIO,&nb);
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;
}
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;
}
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;
}
}
}
ulong banned = loginBanned(&scfg, startup->login_attempt_list, socket, host_name, startup->login_attempt, &attempted);
if(banned || trashcan(&scfg,host_ip,"ip")) {
if(banned) {
char ban_duration[128];
lprintf(LOG_NOTICE, "%04d %s !TEMPORARY BAN of %s (%lu login attempts, last: %s) - remaining: %s"
,socket, client.protocol, host_ip, attempted.count-attempted.dupes, attempted.user, seconds_to_str(banned, ban_duration));
lprintf(LOG_NOTICE,"%04d %s !CLIENT IP ADDRESS BLOCKED: %s",socket, client.protocol, host_ip);
sockprintf(socket,client.protocol,session,"-ERR Access denied.");
mail_close_socket(&socket, &session);
thread_down();
return;
}
if(trashcan(&scfg,host_name,"host")) {
lprintf(LOG_NOTICE,"%04d %s !CLIENT HOSTNAME BLOCKED: %s"
,socket, client.protocol, host_name);
sockprintf(socket,client.protocol,session,"-ERR Access denied.");
mail_close_socket(&socket, &session);
thread_down();
return;
}
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.user=STR_UNKNOWN_USER;
client_on(socket,&client,FALSE /* update */);
SAFEPRINTF2(str,"%s: %s", client.protocol, host_ip);
&& (login_attempts=loginAttempts(startup->login_attempt_list, &pop3.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);
}
do {
memset(&smb,0,sizeof(smb));
memset(&msg,0,sizeof(msg));

rswindell
committed
memset(&user,0,sizeof(user));
password[0]=0;
srand((unsigned int)(time(NULL) ^ (time_t)GetCurrentThreadId())); /* seed random number generator */
rand(); /* throw-away first result */
safe_snprintf(challenge,sizeof(challenge),"<%x%x%lx%lx@%.128s>"
,rand(),socket,(ulong)time(NULL),clock(),startup->host_name);
sockprintf(socket,client.protocol,session,"+OK Synchronet %s Server %s-%s Ready %s"
,client.protocol, revision,PLATFORM_DESC,challenge);
/* Requires USER or APOP command first */
for(i=5;i;i--) {
if(!sockgetrsp(socket,client.protocol,session,NULL,buf,sizeof(buf)))
break;
if(!strnicmp(buf,"USER ",5))
break;
break;
else if (!stricmp(buf, "CAPA")) {
// Capabilities
sockprintf(socket,client.protocol,session, "+OK Capability list follows");
sockprintf(socket,client.protocol,session, "TOP\r\nUSER\r\nPIPELINING\r\nUIDL\r\nIMPLEMENTATION Synchronet POP3 Server %s-%s\r\n%s.", revision, PLATFORM_DESC, (session != -1 || get_ssl_cert(&scfg, NULL, NULL) == -1) ? "" : "STLS\r\n");
i++;
}
else if (!stricmp(buf, "STLS")) {
if (get_ssl_cert(&scfg, &estr, &level) == -1) {
if (estr) {
lprintf(level, "%04d %s !TLS Failure getting certificate: %s", socket, client.protocol, estr);
free_crypt_attrstr(estr);
}
sockprintf(socket,client.protocol,session,"-ERR STLS command not supported");
sockprintf(socket,client.protocol,session,"+OK Begin TLS negotiation");
if ((stat=cryptCreateSession(&session, CRYPT_UNUSED, CRYPT_SESSION_SSL_SERVER)) != CRYPT_OK) {
GCESH(stat, client.protocol, socket, host_ip, CRYPT_UNUSED, "creating 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");
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");
buf[0] = 0;
break;
}
nodelay = TRUE;
setsockopt(socket,IPPROTO_TCP,TCP_NODELAY,(char*)&nodelay,sizeof(nodelay));
nb=0;
ioctlsocket(socket,FIONBIO,&nb);
if ((stat = cryptSetAttribute(session, CRYPT_SESSINFO_NETWORKSOCKET, socket)) != CRYPT_OK) {
unlock_ssl_cert();
GCESH(stat, client.protocol, socket, host_ip, session, "setting network socket");
if ((stat=cryptSetAttribute(session, CRYPT_SESSINFO_ACTIVE, 1)) != CRYPT_OK) {
unlock_ssl_cert();
GCESH(stat, client.protocol, socket, host_ip, session, "setting session active");
unlock_ssl_cert();
if ((stat=cryptSetAttribute(session, CRYPT_OPTION_NET_READTIMEOUT, startup->max_inactivity)) != CRYPT_OK) {
GCESH(stat, client.protocol, socket, host_ip, session, "setting read timeout");
buf[0] = 0;
break;
}
}
i++;
client.protocol = "POP3S";
sockprintf(socket,client.protocol,session,"-ERR USER, APOP, CAPA, or STLS command expected");
if(!i || buf[0]==0) /* no USER or APOP command received */
break;
SKIP_WHITESPACE(p);
if(apop) {
if((response=strrchr(p,' '))!=NULL)
*(response++)=0;
else
response=p;
}
if((p = strstr(username, NO_SPAM)) != NULL) {
*p = 0;
lm_mode = LM_NOSPAM;
} else
lm_mode = 0;
sockprintf(socket,client.protocol,session,"+OK");
if(!sockgetrsp(socket,client.protocol,session,"PASS ",buf,sizeof(buf))) {
sockprintf(socket,client.protocol,session,"-ERR PASS command expected");
SKIP_WHITESPACE(p);
user.number=matchuser(&scfg,username,FALSE /*sysop_alias*/);

rswindell
committed
if(scfg.sys_misc&SM_ECHO_PW)
lprintf(LOG_NOTICE,"%04d %s [%s] !UNKNOWN USER: '%s' (password: %s)"
,socket, client.protocol, host_ip, username, password);

rswindell
committed
else
lprintf(LOG_NOTICE,"%04d %s [%s] !UNKNOWN USER: '%s'"
,socket, client.protocol, host_ip, username);
badlogin(socket, session, client.protocol, pop_err, username, password, host_name, &pop3.client_addr);
break;
}
if((i=getuserdat(&scfg, &user))!=0) {
lprintf(LOG_ERR,"%04d %s [%s] !ERROR %d getting data on user (%s)"
,socket, client.protocol, host_ip, i, username);
badlogin(socket, session, client.protocol, pop_err, NULL, NULL, NULL, NULL);
break;
}
if(user.misc&(DELETED|INACTIVE)) {
lprintf(LOG_NOTICE,"%04d %s [%s] !DELETED or INACTIVE user #%u (%s)"
,socket, client.protocol, host_ip, user.number, username);
badlogin(socket, session, client.protocol, pop_err, NULL, NULL, NULL, NULL);
if(apop) {
strlwr(user.pass); /* this is case-sensitive, so convert to lowercase */
strcat(challenge,user.pass);
MD5_calc(digest,challenge,strlen(challenge));
MD5_hex((BYTE*)str,digest);
lprintf(LOG_NOTICE,"%04d %s [%s] !FAILED APOP authentication: %s"
,socket, client.protocol, host_ip, username);
lprintf(LOG_DEBUG,"%04d !POP3 digest data: %s",socket,challenge);
lprintf(LOG_DEBUG,"%04d !POP3 calc digest: %s",socket,str);
lprintf(LOG_DEBUG,"%04d !POP3 resp digest: %s",socket,response);
badlogin(socket, session, client.protocol, pop_err, username, response, host_name, &pop3.client_addr);
break;
}
} else if(stricmp(password,user.pass)) {

rswindell
committed
if(scfg.sys_misc&SM_ECHO_PW)
lprintf(LOG_NOTICE,"%04d %s [%s] !FAILED Password attempt for user %s: '%s' expected '%s'"
,socket, client.protocol, host_ip, username, password, user.pass);

rswindell
committed
else
lprintf(LOG_NOTICE,"%04d %s [%s] !FAILED Password attempt for user %s"
,socket, client.protocol, host_ip, username);
badlogin(socket, session, client.protocol, pop_err, username, password, host_name, &pop3.client_addr);
if(user.pass[0])
loginSuccess(startup->login_attempt_list, &pop3.client_addr);
putuserrec(&scfg,user.number,U_COMP,LEN_COMP,host_name);
/* Update client display */
client.user=user.alias;
client_on(socket,&client,TRUE /* update */);
if(startup->options&MAIL_OPT_DEBUG_POP3)
lprintf(LOG_INFO,"%04d %s [%s] %s logged in %s", socket, client.protocol, host_ip, user.alias, apop ? "via APOP":"");
SAFEPRINTF2(str,"%s: %s", client.protocol, user.alias);
SAFEPRINTF(smb.file,"%smail",scfg.data_dir);
if(smb_islocked(&smb)) {
lprintf(LOG_WARNING,"%04d %s <%s> !MAIL BASE LOCKED: %s",socket, client.protocol, user.alias, smb.last_error);
sockprintf(socket,client.protocol,session,"-ERR database locked, try again later");
break;
}
smb.retry_time=scfg.smb_retry_time;
smb.subnum=INVALID_SUB;
if((i=smb_open(&smb))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d %s <%s> !ERROR %d (%s) opening %s", socket, client.protocol, user.alias, i, smb.last_error,smb.file);
sockprintf(socket,client.protocol,session,"-ERR %d opening %s",i,smb.file);
break;
}
mail=loadmail(&smb,&msgs,user.number,MAIL_YOUR,lm_mode);
for(l=bytes=0;l<msgs;l++) {
msg.hdr.number=mail[l].number;
if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d %s <%s> !ERROR %d (%s) getting message index"
,socket, client.protocol, user.alias, i, smb.last_error);
if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_WARNING,"%04d %s <%s> !ERROR %d (%s) locking message header #%u"
,socket, client.protocol, user.alias, i, smb.last_error, msg.hdr.number);
break;
}
i=smb_getmsghdr(&smb,&msg);
smb_unlockmsghdr(&smb,&msg);
if(i!=0) {
lprintf(LOG_ERR,"%04d %s <%s> !ERROR %d (%s) line %u, msg #%u"
,socket, client.protocol, user.alias, i, smb.last_error, __LINE__, msg.idx.number);
bytes+=smb_getmsgtxtlen(&msg);
sockprintf(socket,client.protocol,session,"-ERR message #%d: %d (%s)"
,mail[l].number,i,smb.last_error);
break;
}
sockprintf(socket,client.protocol,session,"+OK %u messages (%lu bytes)",msgs,bytes);
while(1) { /* TRANSACTION STATE */
rd = sockreadline(socket, client.protocol, session, buf, sizeof(buf));
if(rd<0)
truncsp(buf);
if(startup->options&MAIL_OPT_DEBUG_POP3)
lprintf(LOG_DEBUG,"%04d %s RX: %s", socket, client.protocol, buf);
sockprintf(socket,client.protocol,session,"+OK");
continue;
}
if(!stricmp(buf, "QUIT")) {
sockprintf(socket,client.protocol,session,"+OK");
break;
}
if(!stricmp(buf, "STAT")) {
sockprintf(socket,client.protocol,session,"+OK %u %lu",msgs,bytes);
continue;
}
if(!stricmp(buf, "RSET")) {
if((i=smb_locksmbhdr(&smb))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d %s <%s> !ERROR %d (%s) locking message base"
,socket, client.protocol, user.alias, i, smb.last_error);
sockprintf(socket,client.protocol,session,"-ERR %d locking message base",i);
continue;
}
for(l=0;l<msgs;l++) {
msg.hdr.number=mail[l].number;
if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d %s <%s> !ERROR %d (%s) getting message index"
,socket, client.protocol, user.alias, i, smb.last_error);
if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_WARNING,"%04d %s <%s> !ERROR %d (%s) locking message header #%u"
,socket, client.protocol, user.alias, i, smb.last_error, msg.hdr.number);
if((i=smb_getmsghdr(&smb,&msg))!=SMB_SUCCESS) {
smb_unlockmsghdr(&smb,&msg);
lprintf(LOG_ERR,"%04d %s <%s> !ERROR %d (%s) line %u, msg #%u"
,socket, client.protocol, user.alias, i, smb.last_error, __LINE__, msg.idx.number);
break;
}
msg.hdr.attr=mail[l].attr;
if((i=smb_putmsg(&smb,&msg))!=SMB_SUCCESS)
lprintf(LOG_ERR,"%04d %s <%s> !ERROR %d (%s) updating message index"
,socket, client.protocol, user.alias, i, smb.last_error);
smb_unlockmsghdr(&smb,&msg);
smb_freemsgmem(&msg);
}
smb_unlocksmbhdr(&smb);
sockprintf(socket,client.protocol,session,"-ERR %d messages reset (ERROR: %d)",l,i);
sockprintf(socket,client.protocol,session,"+OK %u messages (%lu bytes)",msgs,bytes);
continue;
}
if(!strnicmp(buf, "LIST",4) || !strnicmp(buf,"UIDL",4)) {
p=buf+4;
SKIP_WHITESPACE(p);
if(isdigit((uchar)*p)) {
msgnum=strtoul(p, NULL, 10);
if(msgnum<1 || msgnum>msgs) {
lprintf(LOG_NOTICE,"%04d %s <%s> !INVALID message #%" PRIu32
,socket, client.protocol, user.alias, msgnum);
sockprintf(socket,client.protocol,session,"-ERR no such message");
continue;
}
msg.hdr.number=mail[msgnum-1].number;
if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d %s <%s> !ERROR %d (%s) getting message index"
,socket, client.protocol, user.alias, i, smb.last_error);
sockprintf(socket,client.protocol,session,"-ERR %d getting message index",i);
break;
}
if(msg.idx.attr&MSG_DELETE) {
lprintf(LOG_NOTICE,"%04d %s <%s> !ATTEMPT to list DELETED message"
,socket, client.protocol, user.alias);
sockprintf(socket,client.protocol,session,"-ERR message deleted");
if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_WARNING,"%04d %s <%s> !ERROR %d (%s) locking message header #%u"
,socket, client.protocol, user.alias, i, smb.last_error, msg.hdr.number);
sockprintf(socket,client.protocol,session,"-ERR %d locking message header",i);
continue;
}
i=smb_getmsghdr(&smb,&msg);
smb_unlockmsghdr(&smb,&msg);
if(i!=0) {
smb_freemsgmem(&msg);
lprintf(LOG_ERR,"%04d %s <%s> !ERROR %d (%s) line %u, msg #%u"
,socket, client.protocol, user.alias, i, smb.last_error, __LINE__, msg.idx.number);
sockprintf(socket,client.protocol,session,"-ERR %d getting message header",i);
continue;
}
if(!strnicmp(buf, "LIST",4)) {
sockprintf(socket,client.protocol,session,"+OK %" PRIu32 " %lu",msgnum,smb_getmsgtxtlen(&msg));
sockprintf(socket,client.protocol,session,"+OK %" PRIu32 " %u",msgnum,msg.hdr.number);
smb_freemsgmem(&msg);
continue;
}
/* List ALL messages */
sockprintf(socket,client.protocol,session,"+OK %u messages (%lu bytes)",msgs,bytes);
for(l=0;l<msgs;l++) {
msg.hdr.number=mail[l].number;
if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d %s <%s> !ERROR %d (%s) getting message index"
,socket, client.protocol, user.alias, i, smb.last_error);
break;
}
if(msg.idx.attr&MSG_DELETE)
continue;
if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_WARNING,"%04d %s <%s> !ERROR %d (%s) locking message header #%u"
,socket, client.protocol, user.alias, i, smb.last_error, msg.hdr.number);
break;
}
i=smb_getmsghdr(&smb,&msg);
smb_unlockmsghdr(&smb,&msg);
if(i!=0) {
smb_freemsgmem(&msg);
lprintf(LOG_ERR,"%04d %s <%s> !ERROR %d (%s) line %u, msg #%u"
,socket, client.protocol, user.alias, i, smb.last_error, __LINE__, msg.idx.number);
break;
}
if(!strnicmp(buf, "LIST",4)) {
sockprintf(socket,client.protocol,session,"%u %lu",l+1,smb_getmsgtxtlen(&msg));
sockprintf(socket,client.protocol,session,"%u %u",l+1,msg.hdr.number);
smb_freemsgmem(&msg);
}
sockprintf(socket,client.protocol,session,".");
activity=TRUE;
if(!strnicmp(buf, "RETR ",5) || !strnicmp(buf,"TOP ",4)) {
SAFEPRINTF2(str,"%s: %s", client.protocol, user.alias);
status(str);
lines=-1;
p=buf+4;
SKIP_WHITESPACE(p);
msgnum=strtoul(p, NULL, 10);
if(!strnicmp(buf,"TOP ",4)) {
SKIP_DIGIT(p);
SKIP_WHITESPACE(p);
lines=atol(p);
}
if(msgnum<1 || msgnum>msgs) {
lprintf(LOG_NOTICE,"%04d %s <%s> !ATTEMPTED to retrieve an INVALID message #%" PRIu32
,socket, client.protocol, user.alias, msgnum);
sockprintf(socket,client.protocol,session,"-ERR no such message");
continue;
}
msg.hdr.number=mail[msgnum-1].number;
lprintf(LOG_INFO,"%04d %s <%s> retrieving message #%u with command: %s"
,socket, client.protocol, user.alias, msg.hdr.number, buf);
if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d %s <%s> !ERROR %d (%s) getting message index"
,socket, client.protocol, user.alias, i, smb.last_error);
sockprintf(socket,client.protocol,session,"-ERR %d getting message index",i);
continue;
}
if(msg.idx.attr&MSG_DELETE) {
lprintf(LOG_NOTICE,"%04d %s <%s> !ATTEMPT to retrieve DELETED message"
,socket, client.protocol, user.alias);
sockprintf(socket,client.protocol,session,"-ERR message deleted");
if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_WARNING,"%04d %s <%s> !ERROR %d (%s) locking message header #%u"
,socket, client.protocol, user.alias, i, smb.last_error, msg.hdr.number);
sockprintf(socket,client.protocol,session,"-ERR %d locking message header",i);
i=smb_getmsghdr(&smb,&msg);
smb_unlockmsghdr(&smb,&msg);
if(i!=0) {
lprintf(LOG_ERR,"%04d %s <%s> !ERROR %d (%s) line %u, msg #%u"
,socket, client.protocol, user.alias, i, smb.last_error, __LINE__, msg.idx.number);
sockprintf(socket,client.protocol,session,"-ERR %d getting message header",i);
if((msgtxt=smb_getmsgtxt(&smb,&msg,GETMSGTXT_ALL))==NULL) {
lprintf(LOG_ERR,"%04d %s <%s> !ERROR (%s) retrieving message #%u text"
,socket, client.protocol, user.alias, smb.last_error, msg.hdr.number);
sockprintf(socket,client.protocol,session,"-ERR retrieving message text");
remove_ctrl_a(msgtxt, msgtxt);
if(lines > 0 /* Works around BlackBerry mail server */
&& lines >= strlen(msgtxt)) /* which requests the number of bytes (instead of lines) using TOP */
lines=-1;
sockprintf(socket,client.protocol,session,"+OK message follows");
lprintf(LOG_DEBUG,"%04d %s <%s> sending message text (%lu bytes)"
,socket, client.protocol, user.alias, (ulong)strlen(msgtxt));
lines_sent=sockmsgtxt(socket, client.protocol, session, &msg, msgtxt, lines);
/* if(startup->options&MAIL_OPT_DEBUG_POP3) */
if(lines!=-1 && lines_sent<lines) /* could send *more* lines */
lprintf(LOG_WARNING,"%04d %s <%s> !ERROR sending message text (sent %ld of %ld lines)"
,socket, client.protocol, user.alias, lines_sent, lines);
lprintf(LOG_DEBUG,"%04d %s <%s> message transfer complete (%lu lines)"
,socket, client.protocol, user.alias, lines_sent);
if((i=smb_locksmbhdr(&smb))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d %s <%s> !ERROR %d (%s) locking message base"
,socket, client.protocol, user.alias, i, smb.last_error);
} else {
if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d %s <%s> !ERROR %d (%s) getting message index"
,socket, client.protocol, user.alias, i, smb.last_error);
} else {
msg.hdr.attr|=MSG_READ;
if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS)
lprintf(LOG_ERR,"%04d %s <%s> !ERROR %d (%s) locking message header #%u"
,socket, client.protocol, user.alias, i, smb.last_error, msg.hdr.number);
if((i=smb_putmsg(&smb,&msg))!=SMB_SUCCESS)
lprintf(LOG_ERR,"%04d %s <%s> !ERROR %d (%s) marking message #%u as read"
,socket, client.protocol, user.alias, i, smb.last_error, msg.hdr.number);
smb_unlockmsghdr(&smb,&msg);
}
smb_unlocksmbhdr(&smb);
}
smb_freemsgmem(&msg);
smb_freemsgtxt(msgtxt);
continue;
}
if(!strnicmp(buf, "DELE ",5)) {
p=buf+5;
SKIP_WHITESPACE(p);
msgnum=strtoul(p, NULL, 10);
if(msgnum<1 || msgnum>msgs) {
lprintf(LOG_NOTICE,"%04d %s <%s> !ATTEMPTED to delete an INVALID message #%" PRIu32
,socket, client.protocol, user.alias, msgnum);
sockprintf(socket,client.protocol,session,"-ERR no such message");
continue;
}
msg.hdr.number=mail[msgnum-1].number;
lprintf(LOG_INFO,"%04d %s <%s> deleting message #%u"
,socket, client.protocol, user.alias, msg.hdr.number);
if((i=smb_locksmbhdr(&smb))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d %s <%s> !ERROR %d (%s) locking message base"
,socket, client.protocol, user.alias, i, smb.last_error);
sockprintf(socket,client.protocol,session,"-ERR %d locking message base",i);
continue;
}
if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
smb_unlocksmbhdr(&smb);
lprintf(LOG_ERR,"%04d %s <%s> !ERROR %d (%s) getting message index"
,socket, client.protocol, user.alias, i, smb.last_error);
sockprintf(socket,client.protocol,session,"-ERR %d getting message index",i);
if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS) {
smb_unlocksmbhdr(&smb);
lprintf(LOG_WARNING,"%04d %s <%s> !ERROR %d (%s) locking message header #%u"
,socket, client.protocol, user.alias, i, smb.last_error, msg.hdr.number);
sockprintf(socket,client.protocol,session,"-ERR %d locking message header",i);
if((i=smb_getmsghdr(&smb,&msg))!=SMB_SUCCESS) {
smb_unlocksmbhdr(&smb);
lprintf(LOG_ERR,"%04d %s <%s> !ERROR %d (%s) line %u, msg #%u"
,socket, client.protocol, user.alias, i, smb.last_error, __LINE__, msg.idx.number);
sockprintf(socket,client.protocol,session,"-ERR %d getting message header",i);
continue;
}
msg.hdr.attr|=MSG_DELETE;
if((i=smb_putmsg(&smb,&msg))==SMB_SUCCESS && msg.hdr.auxattr&MSG_FILEATTACH)
delfattach(&scfg,&msg);
smb_unlockmsghdr(&smb,&msg);
smb_unlocksmbhdr(&smb);
smb_freemsgmem(&msg);
if(i!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d %s <%s> !ERROR %d (%s) marking message as read"
, socket, client.protocol, user.alias, i, smb.last_error);
sockprintf(socket,client.protocol,session,"-ERR %d marking message for deletion",i);
sockprintf(socket,client.protocol,session,"+OK");
if(startup->options&MAIL_OPT_DEBUG_POP3)
lprintf(LOG_INFO,"%04d %s <%s> message deleted", socket, client.protocol, user.alias);
lprintf(LOG_NOTICE,"%04d %s <%s> !UNSUPPORTED COMMAND: '%s'"
,socket, client.protocol, user.alias, buf);
sockprintf(socket,client.protocol,session,"-ERR UNSUPPORTED COMMAND: %s",buf);
if(user.number) {
if(!logoutuserdat(&scfg,&user,time(NULL),client.time))
lprintf(LOG_ERR,"%04d %s <%s> !ERROR in logoutuserdat", socket, client.protocol, user.alias);
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);
lprintf(LOG_INFO,"%04d %s client disconnected from port %u on %s [%s]"
,socket, client.protocol, inet_addrport(&pop3.client_addr), host_name, host_ip);
status(STATUS_WFC);
/* Free up resources here */
if(mail!=NULL)
freemail(mail);
smb_freemsgmem(&msg);
smb_close(&smb);
protected_uint32_adjust(&active_clients, -1);
update_clients();
{
int32_t remain = thread_down();
if(startup->options&MAIL_OPT_DEBUG_POP3)
lprintf(LOG_DEBUG,"%04d %s session thread terminated (%u threads remain, %lu clients served)"
,socket, client.protocol, remain, ++stats.pop3_served);
/* Must be last */
mail_close_socket(&socket, &session);
static ulong rblchk(SOCKET sock, const char* prot, union xp_sockaddr *addr, const char* rbl_addr)
{
char name[256];
DWORD mail_addr;
HOSTENT* host;
struct in_addr dnsbl_result;
unsigned char *addr6;
switch(addr->addr.sa_family) {
case AF_INET:
mail_addr=ntohl(addr->in.sin_addr.s_addr);
safe_snprintf(name,sizeof(name),"%lu.%lu.%lu.%lu.%.128s"
,(ulong)(mail_addr&0xff)
,(ulong)(mail_addr>>8)&0xff
,(ulong)(mail_addr>>16)&0xff
,(ulong)(mail_addr>>24)&0xff
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
,rbl_addr
);
break;
case AF_INET6:
addr6 = (unsigned char *)&addr->in6.sin6_addr;
safe_snprintf(name,sizeof(name),"%1x.%1x.%1x.%1x.%1x.%1x.%1x.%1x."
"%1x.%1x.%1x.%1x.%1x.%1x.%1x.%1x."
"%1x.%1x.%1x.%1x.%1x.%1x.%1x.%1x."
"%1x.%1x.%1x.%1x.%1x.%1x.%1x.%1x.%.128s"
,addr6[15]&0x0f
,addr6[15]>>4
,addr6[14]&0x0f
,addr6[14]>>4
,addr6[13]&0x0f
,addr6[13]>>4
,addr6[12]&0x0f
,addr6[12]>>4
,addr6[11]&0x0f
,addr6[11]>>4
,addr6[10]&0x0f
,addr6[10]>>4
,addr6[9]&0x0f
,addr6[9]>>4
,addr6[8]&0x0f
,addr6[8]>>4
,addr6[7]&0x0f
,addr6[7]>>4
,addr6[6]&0x0f
,addr6[6]>>4
,addr6[5]&0x0f
,addr6[5]>>4
,addr6[4]&0x0f
,addr6[4]>>4
,addr6[3]&0x0f
,addr6[3]>>4
,addr6[2]&0x0f
,addr6[2]>>4
,addr6[1]&0x0f
,addr6[1]>>4
,addr6[0]&0x0f
,addr6[0]>>4
,rbl_addr
);
break;
default:
return 0;
}
lprintf(LOG_DEBUG,"%04d %s DNSBL Query: %s",sock,prot,name);
if((host=gethostbyname(name))==NULL)
return(0);
dnsbl_result.s_addr = *((ulong*)host->h_addr_list[0]);
lprintf(LOG_INFO,"%04d %s DNSBL Query: %s resolved to: %s"
,sock,prot,name,inet_ntoa(dnsbl_result));
return(dnsbl_result.s_addr);
static ulong dns_blacklisted(SOCKET sock, const char* prot, union xp_sockaddr *addr, char* host_name, char* list, char* dnsbl_ip)
{
char fname[MAX_PATH+1];
char str[256];
char* p;
char* tp;
FILE* fp;
ulong found=0;
SAFEPRINTF(fname,"%sdnsbl_exempt.cfg",scfg.ctrl_dir);
if(findstr(host_name,fname))
return(FALSE);
SAFEPRINTF(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)
break;
truncsp(str);
p=str;
SKIP_WHITESPACE(p);
if(*p==';' || *p==0) /* comment or blank line */
continue;
sprintf(list,"%.100s",p);
/* terminate */
tp = p;
FIND_WHITESPACE(tp);
*tp=0;
found = rblchk(sock, prot, addr, p);
}
fclose(fp);
if(found)
return(found);
}
static BOOL chk_email_addr(SOCKET socket, const char* prot, char* p, char* host_name, char* host_ip
,char* to, char* from, char* source)
{
char addr[64];
char tmp[128];
SKIP_WHITESPACE(p);
char* lt = strchr(p, '<');
if(lt!= NULL)
p = lt+1;
truncstr(addr,">( ");
if(!trashcan(&scfg,addr,"email"))
return(TRUE);
lprintf(LOG_NOTICE,"%04d %s !BLOCKED %s e-mail address: %s"
,socket, prot, source, addr);
SAFEPRINTF2(tmp,"Blocked %s e-mail address: %s", source, addr);
spamlog(&scfg, (char*)prot, "REFUSED", tmp, host_name, host_ip, to, from);
static BOOL email_addr_is_exempt(const char* addr)
{
char fname[MAX_PATH+1];
char netmail[128];
char* p;
if(*addr==0 || strcmp(addr,"<>")==0)
return FALSE;
SAFEPRINTF(fname,"%sdnsbl_exempt.cfg",scfg.ctrl_dir);
if(findstr((char*)addr,fname))
return TRUE;
SAFECOPY(netmail, addr);
if(*(p=netmail)=='<')
p++;
truncstr(p,">");
return userdatdupe(&scfg, 0, U_NETMAIL, LEN_NETMAIL, p, /* del */FALSE, /* next */FALSE, NULL, NULL);
}
static void exempt_email_addr(const char* comment
,const char* fromname, const char* fromext, const char* fromaddr
,const char* toaddr)
{
char fname[MAX_PATH+1];
char to[128];
char tmp[128];
FILE* fp;
if(*toaddr == '<')
SAFECOPY(to, toaddr);
else
SAFEPRINTF(to,"<%s>",toaddr);
if(!email_addr_is_exempt(to)) {
SAFEPRINTF(fname,"%sdnsbl_exempt.cfg",scfg.ctrl_dir);
if((fp=fopen(fname,"a"))==NULL)
lprintf(LOG_ERR,"0000 !Error opening file: %s", fname);
else {
lprintf(LOG_INFO,"0000 %s: %s", comment, to);
fprintf(fp,"\n;%s from \"%s\""
,comment, fromname);
if(fromext!=NULL)
fprintf(fp,"%s",fromext);
fprintf(fp," %s on %s\n%s\n"
,fromaddr, timestr(&scfg,time32(NULL),tmp), to);
fclose(fp);
}
}
}
{
int file;
if(scfg.smtpmail_sem[0]==0)
return; /* do nothing */
if((file=open(scfg.smtpmail_sem,O_WRONLY|O_CREAT|O_TRUNC,DEFFILEMODE))!=-1)
close(file);
}
/*****************************************************************************/
/* Returns command line generated from instr with %c replacements */
/*****************************************************************************/
static char* mailcmdstr(char* instr, char* msgpath, char* newpath, char* logpath
,char* lstpath, char* errpath
,char* host, char* ip, uint usernum
,char* rcpt_addr
,char* sender, char* sender_addr, char* reverse_path, char* cmd)
{
char str[1024];
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 'D':
strcat(cmd,logpath);
break;
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 'N':
strcat(cmd,newpath);
break;
case 'O': /* SysOp */
strcat(cmd,scfg.sys_op);
break;
case 'Q': /* QWK ID */
strcat(cmd,scfg.sys_id);
break;
case 'R': /* reverse path */
strcat(cmd,reverse_path);
break;
case 'S': /* sender name */
strcat(cmd,sender);
break;
case 'T': /* recipient */
strcat(cmd,rcpt_addr);
break;
case 'A': /* sender address */
strcat(cmd,sender_addr);
break;
case 'V': /* Synchronet Version */
SAFEPRINTF2(str,"%s%c",VERSION,REVISION);
strcat(cmd,str);
break;
case 'Z':
strcat(cmd,scfg.text_dir);
break;
case '!': /* EXEC Directory */
strcat(cmd,scfg.exec_dir);
break;
case '@': /* EXEC Directory for DOS/OS2/Win32, blank for Unix */
#ifndef __unix__
strcat(cmd,scfg.exec_dir);
#endif
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 */
strcat(cmd,str);
break;