mirror of
https://bitbucket.org/jsuto/piler.git
synced 2024-11-07 21:31:58 +01:00
first demo of the new architecture
Change-Id: Id76636f30173465fbd0e8516d99017b4336de4db Signed-off-by: SJ <sj@acts.hu>
This commit is contained in:
parent
6783f9eec5
commit
5f5585d519
4
configure
vendored
4
configure
vendored
@ -4645,7 +4645,7 @@ fi
|
||||
|
||||
if test "$os" = "FreeBSD"; then
|
||||
defs="$defs -DFREEBSD"
|
||||
antispam_libs="-lz -lm -lcrypto -lssl"
|
||||
antispam_libs="-lz -lm -lcrypto -lssl -liconv"
|
||||
MAKE="gmake"
|
||||
fi
|
||||
|
||||
@ -4866,7 +4866,7 @@ echo; echo
|
||||
|
||||
CFLAGS="$static -O2 -Wall -g"
|
||||
LIBS="$antispam_libs $sunos_libs "
|
||||
OBJS="dirs.o base64.o misc.o counters.o cfg.o sig.o decoder.o hash.o parser.o parser_utils.o rules.o smtp.o session.o message.o attachment.o digest.o store.o archive.o tai.o import.o import_maildir.o import_mailbox.o import_pop3.o import_imap.o import_gui.o imap.o pop3.o extract.o mydomains.o $objs"
|
||||
OBJS="dirs.o base64.o misc.o counters.o cfg.o sig.o decoder.o hash.o parser.o parser_utils.o rules.o smtp.o bdat.o message.o attachment.o digest.o store.o archive.o tai.o import.o import_maildir.o import_mailbox.o import_pop3.o import_imap.o import_gui.o imap.o pop3.o extract.o mydomains.o $objs"
|
||||
|
||||
ac_config_files="$ac_config_files Makefile src/Makefile etc/Makefile util/Makefile init.d/Makefile unit_tests/Makefile contrib/imap/Makefile"
|
||||
|
||||
|
@ -544,7 +544,7 @@ echo; echo
|
||||
|
||||
CFLAGS="$static -O2 -Wall -g"
|
||||
LIBS="$antispam_libs $sunos_libs "
|
||||
OBJS="dirs.o base64.o misc.o counters.o cfg.o sig.o decoder.o hash.o parser.o parser_utils.o rules.o smtp.o session.o message.o attachment.o digest.o store.o archive.o tai.o import.o import_maildir.o import_mailbox.o import_pop3.o import_imap.o import_gui.o imap.o pop3.o extract.o mydomains.o $objs"
|
||||
OBJS="dirs.o base64.o misc.o counters.o cfg.o sig.o decoder.o hash.o parser.o parser_utils.o rules.o smtp.o bdat.o message.o attachment.o digest.o store.o archive.o tai.o import.o import_maildir.o import_mailbox.o import_pop3.o import_imap.o import_gui.o imap.o pop3.o extract.o mydomains.o $objs"
|
||||
|
||||
AC_CONFIG_FILES([Makefile src/Makefile etc/Makefile util/Makefile init.d/Makefile unit_tests/Makefile contrib/imap/Makefile])
|
||||
AC_OUTPUT
|
||||
|
@ -33,7 +33,7 @@ MAKE = `which make`
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
|
||||
all: libpiler.a piler pilerconf pilerget pileraget pilerimport pilerexport pilerpurge reindex test
|
||||
all: libpiler.a piler pilerconf pilerget pileraget pilerimport pilerexport pilerpurge reindex test piler-smtp
|
||||
install: install-piler
|
||||
|
||||
|
||||
@ -47,6 +47,8 @@ libpiler.a: $(OBJS) $(SQL_OBJS)
|
||||
ln -sf libpiler.so.$(LIBPILER_VERSION) libpiler.so
|
||||
ln -sf libpiler.so.$(LIBPILER_VERSION) libpiler.so.$(PILER_VERSION)
|
||||
|
||||
piler-smtp: piler-smtp.c libpiler.a
|
||||
$(CC) $(CFLAGS) $(INCDIR) $(DEFS) -o $@ $< cfg.o misc.o tai.o smtp.o dirs.o sig.o bdat.o $(LIBS) $(LIBDIR)
|
||||
|
||||
pilerget: pilerget.c libpiler.a
|
||||
$(CC) $(CFLAGS) $(INCDIR) $(DEFS) -o $@ $< -lpiler $(LIBS) $(LIBDIR)
|
||||
@ -83,6 +85,7 @@ install-piler:
|
||||
(cd $(DESTDIR)$(libdir) && ln -sf libpiler.so.$(LIBPILER_VERSION) libpiler.so.$(PILER_VERSION))
|
||||
|
||||
$(INSTALL) -m 0755 piler $(DESTDIR)$(sbindir)
|
||||
$(INSTALL) -m 0755 piler-smtp $(DESTDIR)$(sbindir)
|
||||
$(INSTALL) -m 0755 pilerconf $(DESTDIR)$(sbindir)
|
||||
$(INSTALL) -m 6755 -o $(RUNNING_USER) -g $(RUNNING_GROUP) pilerget $(DESTDIR)$(bindir)
|
||||
$(INSTALL) -m 6755 -o $(RUNNING_USER) -g $(RUNNING_GROUP) pileraget $(DESTDIR)$(bindir)
|
||||
@ -93,7 +96,7 @@ install-piler:
|
||||
$(INSTALL) -m 6755 -o $(RUNNING_USER) -g $(RUNNING_GROUP) pilertest $(DESTDIR)$(bindir)
|
||||
|
||||
clean:
|
||||
rm -f *.o *.a libpiler.so* piler pilerconf pilerget pileraget pilerimport pilerexport pilerpurge pilertest reindex
|
||||
rm -f *.o *.a libpiler.so* piler pilerconf pilerget pileraget pilerimport pilerexport pilerpurge pilertest reindex piler-smtp
|
||||
|
||||
distclean: clean
|
||||
rm -f Makefile
|
||||
|
136
src/bdat.c
Normal file
136
src/bdat.c
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* bdat.c, SJ
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <piler.h>
|
||||
#include <smtp.h>
|
||||
|
||||
|
||||
void reset_bdat_counters(struct smtp_session *session){
|
||||
session->bdat_rounds = 0;
|
||||
session->bdat_last_round = 0;
|
||||
session->bdat_bytes_to_read = 0;
|
||||
session->bad = 0;
|
||||
}
|
||||
|
||||
|
||||
void get_bdat_size_to_read(struct smtp_session *session, char *buf){
|
||||
char *p;
|
||||
|
||||
session->bdat_rounds++;
|
||||
session->bdat_bytes_to_read = 0;
|
||||
|
||||
session->protocol_state = SMTP_STATE_BDAT;
|
||||
|
||||
// determine if this is the last BDAT command
|
||||
|
||||
p = strcasestr(buf, " LAST");
|
||||
if(p){
|
||||
session->bdat_last_round = 1;
|
||||
syslog(LOG_INFO, "%s: BDAT LAST", session->ttmpfile);
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
// determine the size to be read
|
||||
|
||||
p = strchr(buf, ' ');
|
||||
if(p){
|
||||
session->bdat_bytes_to_read = atoi(p);
|
||||
if(session->cfg->verbosity >= _LOG_DEBUG) syslog(LOG_INFO, "%s: BDAT len=%d", session->ttmpfile, session->bdat_bytes_to_read);
|
||||
}
|
||||
|
||||
if(!p || session->bdat_bytes_to_read <= 0){
|
||||
session->bdat_bytes_to_read = 0;
|
||||
syslog(LOG_INFO, "%s: malformed BDAT command", session->ttmpfile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void process_bdat(struct smtp_session *session, char *readbuf, int readlen){
|
||||
int i;
|
||||
char buf[SMALLBUFSIZE];
|
||||
|
||||
if(readlen <= 0) return;
|
||||
|
||||
//printf("readbuf in process_bdat (%d): *%s*\n", readlen, readbuf);
|
||||
|
||||
if(session->bdat_rounds == 1){
|
||||
session->fd = open(session->ttmpfile, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP);
|
||||
if(session->fd == -1){
|
||||
syslog(LOG_PRIORITY, "%s: %s", ERR_OPEN_TMP_FILE, session->ttmpfile);
|
||||
}
|
||||
}
|
||||
|
||||
session->bdat_bytes_to_read -= readlen;
|
||||
|
||||
if(session->fd != -1){
|
||||
write(session->fd, readbuf, readlen);
|
||||
session->tot_len += readlen;
|
||||
|
||||
if(session->cfg->verbosity >= _LOG_DEBUG) syslog(LOG_INFO, "%s: wrote %d bytes, %d bytes to go", session->ttmpfile, readlen, session->bdat_bytes_to_read);
|
||||
}
|
||||
|
||||
|
||||
if(session->bdat_bytes_to_read < 0){
|
||||
// malformed data from client: we got more data then had been told in BDAT argument
|
||||
syslog(LOG_PRIORITY, "ERROR: invalid BDAT data. Expected %d, got %d bytes", session->bdat_bytes_to_read + readlen, readlen);
|
||||
session->bad = 1;
|
||||
|
||||
close(session->fd);
|
||||
unlink(session->ttmpfile);
|
||||
}
|
||||
|
||||
if(session->bdat_bytes_to_read == 0){
|
||||
|
||||
if(session->bdat_last_round == 1){
|
||||
if(session->cfg->verbosity >= _LOG_DEBUG) syslog(LOG_INFO, "%s: read all bdat data in %d rounds", session->ttmpfile, session->bdat_rounds);
|
||||
|
||||
// send back the smtp answers
|
||||
for(i=0; i<session->bdat_rounds; i++){
|
||||
if(session->fd == -1){
|
||||
send_smtp_response(session, SMTP_RESP_421_ERR_WRITE_FAILED);
|
||||
}
|
||||
else {
|
||||
if(i == 0){
|
||||
fsync(session->fd);
|
||||
close(session->fd);
|
||||
|
||||
move_email(session);
|
||||
|
||||
snprintf(buf, sizeof(buf)-1, "250 OK <%s>\r\n", session->ttmpfile);
|
||||
send_smtp_response(session, buf);
|
||||
syslog(LOG_PRIORITY, "received: %s, from=%s, size=%d", session->ttmpfile, session->mailfrom, session->tot_len);
|
||||
}
|
||||
else send_smtp_response(session, SMTP_RESP_250_BDAT);
|
||||
}
|
||||
}
|
||||
|
||||
// technically we are not in the PERIOD state, but it's good enough
|
||||
// to quit the BDAT processing state
|
||||
session->protocol_state = SMTP_STATE_PERIOD;
|
||||
|
||||
session->fd = -1;
|
||||
}
|
||||
|
||||
else {
|
||||
// this is not the last BDAT round, let's go back
|
||||
// after the rcpt state, and wait for the next
|
||||
// BDAT command
|
||||
session->protocol_state = SMTP_STATE_RCPT_TO;
|
||||
}
|
||||
}
|
||||
}
|
@ -101,6 +101,7 @@ struct _parse_rule config_parse_rules[] =
|
||||
{ "process_rcpt_to_addresses", "integer", (void*) int_parser, offsetof(struct __config, process_rcpt_to_addresses), "0", sizeof(int)},
|
||||
{ "queuedir", "string", (void*) string_parser, offsetof(struct __config, queuedir), QUEUE_DIR, MAXVAL-1},
|
||||
{ "server_id", "integer", (void*) int_parser, offsetof(struct __config, server_id), "0", sizeof(int)},
|
||||
{ "smtp_timeout", "integer", (void*) int_parser, offsetof(struct __config, smtp_timeout), "60", sizeof(int)},
|
||||
{ "spam_header_line", "string", (void*) string_parser, offsetof(struct __config, spam_header_line), "", MAXVAL-1},
|
||||
{ "syslog_recipients", "integer", (void*) int_parser, offsetof(struct __config, syslog_recipients), "0", sizeof(int)},
|
||||
{ "tls_enable", "integer", (void*) int_parser, offsetof(struct __config, tls_enable), "0", sizeof(int)},
|
||||
|
@ -48,6 +48,7 @@ struct __config {
|
||||
int verbosity;
|
||||
char locale[MAXVAL];
|
||||
|
||||
int smtp_timeout;
|
||||
int helper_timeout;
|
||||
int extract_attachments;
|
||||
|
||||
|
@ -11,9 +11,9 @@
|
||||
|
||||
#define PROGNAME "piler"
|
||||
|
||||
#define VERSION "1.2.0"
|
||||
#define VERSION "1.3.0-master"
|
||||
|
||||
#define BUILD 952
|
||||
#define BUILD 975
|
||||
|
||||
#define HOSTID "mailarchiver"
|
||||
|
||||
|
26
src/defs.h
26
src/defs.h
@ -22,6 +22,7 @@
|
||||
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <netinet/in.h>
|
||||
#include "tai.h"
|
||||
#include "config.h"
|
||||
|
||||
@ -64,9 +65,6 @@
|
||||
#define RULE_NO_MATCH -100
|
||||
|
||||
|
||||
typedef void signal_func (int);
|
||||
|
||||
|
||||
struct child {
|
||||
pid_t pid;
|
||||
int serial;
|
||||
@ -386,6 +384,26 @@ struct session_ctx {
|
||||
struct counters *counters;
|
||||
};
|
||||
|
||||
struct smtp_session {
|
||||
char ttmpfile[SMALLBUFSIZE];
|
||||
char mailfrom[SMALLBUFSIZE];
|
||||
char buf[SMALLBUFSIZE];
|
||||
char remote_host[INET6_ADDRSTRLEN];
|
||||
time_t lasttime;
|
||||
int protocol_state;
|
||||
int fd;
|
||||
int bad;
|
||||
int buflen;
|
||||
int tot_len;
|
||||
int bdat_rounds;
|
||||
int bdat_last_round;
|
||||
int bdat_bytes_to_read;
|
||||
int socket;
|
||||
struct __config *cfg;
|
||||
SSL_CTX *ctx;
|
||||
SSL *ssl;
|
||||
int use_ssl;
|
||||
int starttls;
|
||||
};
|
||||
|
||||
#endif /* _DEFS_H */
|
||||
|
||||
|
@ -18,6 +18,7 @@ void createdir(char *path, uid_t uid, gid_t gid, mode_t mode);
|
||||
|
||||
void check_and_create_directories(struct __config *cfg, uid_t uid, gid_t gid){
|
||||
char *p, s[SMALLBUFSIZE];
|
||||
int i;
|
||||
|
||||
p = strrchr(cfg->workdir, '/');
|
||||
if(p){
|
||||
@ -45,6 +46,11 @@ void check_and_create_directories(struct __config *cfg, uid_t uid, gid_t gid){
|
||||
*p = '/';
|
||||
}
|
||||
|
||||
for(i=0; i<cfg->number_of_worker_processes; i++){
|
||||
snprintf(s, sizeof(s)-1, "%s/%d", cfg->workdir, i);
|
||||
createdir(s, uid, gid, 0700);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
27
src/misc.c
27
src/misc.c
@ -107,6 +107,21 @@ int searchStringInBuffer(char *s, int len1, char *what, int len2){
|
||||
}
|
||||
|
||||
|
||||
int search_char_backward(char *buf, int buflen, char c){
|
||||
int n, m;
|
||||
|
||||
m = buflen - 1 - 5;
|
||||
if(m < 0) m = 0;
|
||||
|
||||
for(n=m; n<buflen; n++){
|
||||
if(*(buf + n) == c){
|
||||
return n;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* count a character in buffer
|
||||
*/
|
||||
@ -627,6 +642,17 @@ int can_i_write_current_directory(){
|
||||
}
|
||||
|
||||
|
||||
void move_email(struct smtp_session *session){
|
||||
char buf[SMALLBUFSIZE];
|
||||
|
||||
snprintf(buf, sizeof(buf)-1, "%d/%s", session->ttmpfile[RND_STR_LEN-1] % session->cfg->number_of_worker_processes, session->ttmpfile);
|
||||
|
||||
if(rename(session->ttmpfile, buf)){
|
||||
syslog(LOG_PRIORITY, "ERROR: couldn't rename %s to %s", session->ttmpfile, buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
char *strcasestr(const char *s, const char *find){
|
||||
char c, sc;
|
||||
@ -647,4 +673,3 @@ char *strcasestr(const char *s, const char *find){
|
||||
return((char*)s);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -20,6 +20,7 @@ void get_extractor_list();
|
||||
void __fatal(char *s);
|
||||
long tvdiff(struct timeval a, struct timeval b);
|
||||
int searchStringInBuffer(char *s, int len1, char *what, int len2);
|
||||
int search_char_backward(char *buf, int buflen, char c);
|
||||
int countCharacterInBuffer(char *p, char c);
|
||||
void replaceCharacterInBuffer(char *p, char from, char to);
|
||||
char *split(char *str, int ch, char *buf, int buflen, int *result);
|
||||
@ -46,6 +47,8 @@ void *get_in_addr(struct sockaddr *sa);
|
||||
|
||||
int can_i_write_current_directory();
|
||||
|
||||
void move_email(struct smtp_session *session);
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
char *strcasestr(const char *s, const char *find);
|
||||
#endif
|
||||
|
472
src/piler-smtp.c
Normal file
472
src/piler-smtp.c
Normal file
@ -0,0 +1,472 @@
|
||||
/*
|
||||
* piler-smtp.c
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <signal.h>
|
||||
#include <poll.h>
|
||||
#include <netinet/in.h>
|
||||
#include <locale.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <syslog.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <piler.h>
|
||||
|
||||
#define POLL_SIZE 256
|
||||
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
|
||||
struct pollfd poll_set[POLL_SIZE];
|
||||
int timeout = 20; // checking for timeout this often [sec]
|
||||
int numfds = 0;
|
||||
int listenerfd = -1;
|
||||
|
||||
char *configfile = CONFIG_FILE;
|
||||
struct __config cfg;
|
||||
struct passwd *pwd;
|
||||
struct smtp_session *session, *sessions[POLL_SIZE];
|
||||
|
||||
|
||||
void handle_data(struct smtp_session *session, char *readbuf, int readlen){
|
||||
char *p, puf[MAXBUFSIZE];
|
||||
int result;
|
||||
|
||||
// process BDAT stuff
|
||||
|
||||
if(session->protocol_state == SMTP_STATE_BDAT){
|
||||
if(session->bad == 1){
|
||||
// something bad happened in the BDAT processing
|
||||
return;
|
||||
}
|
||||
|
||||
process_bdat(session, readbuf, readlen);
|
||||
}
|
||||
|
||||
// process DATA
|
||||
|
||||
else if(session->protocol_state == SMTP_STATE_DATA){
|
||||
process_data(session, readbuf, readlen);
|
||||
}
|
||||
|
||||
// process other SMTP commands
|
||||
|
||||
else {
|
||||
//printf("len=%d, buf=*%s*\n\n\n", readlen, readbuf);
|
||||
|
||||
if(session->buflen > 0){
|
||||
snprintf(puf, sizeof(puf)-1, "%s%s", session->buf, readbuf);
|
||||
snprintf(readbuf, BIGBUFSIZE-1, "%s", puf);
|
||||
|
||||
session->buflen = 0;
|
||||
memset(session->buf, 0, SMALLBUFSIZE);
|
||||
}
|
||||
|
||||
p = readbuf;
|
||||
|
||||
do {
|
||||
memset(puf, 0, sizeof(puf));
|
||||
p = split(p, '\n', puf, sizeof(puf)-1, &result);
|
||||
|
||||
if(puf[0] == '\0') continue;
|
||||
|
||||
if(result == 1){
|
||||
process_smtp_command(session, puf);
|
||||
|
||||
// if chunking is enabled and we have data after BDAT <len>
|
||||
// then process the rest
|
||||
|
||||
if(session->cfg->enable_chunking == 1 && p && session->protocol_state == SMTP_STATE_BDAT){
|
||||
process_bdat(session, p, strlen(p));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
snprintf(session->buf, SMALLBUFSIZE-1, "%s", puf);
|
||||
session->buflen = strlen(puf);
|
||||
}
|
||||
} while(p);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void init_smtp_session(struct smtp_session *session, int fd_index, int sd){
|
||||
session->socket = sd;
|
||||
session->buflen = 0;
|
||||
session->protocol_state = SMTP_STATE_INIT;
|
||||
|
||||
session->cfg = &cfg;
|
||||
|
||||
session->use_ssl = 0; // use SSL/TLS
|
||||
session->starttls = 0; // SSL/TLS communication is active (1) or not (0)
|
||||
session->ctx = NULL;
|
||||
session->ssl = NULL;
|
||||
|
||||
memset(session->buf, 0, SMALLBUFSIZE);
|
||||
memset(session->remote_host, 0, INET6_ADDRSTRLEN);
|
||||
|
||||
reset_bdat_counters(session);
|
||||
|
||||
time(&(session->lasttime));
|
||||
}
|
||||
|
||||
|
||||
void free_smtp_session(struct smtp_session *session){
|
||||
|
||||
if(session){
|
||||
//printf("freeing session\n");
|
||||
|
||||
if(session->use_ssl == 1){
|
||||
//printf("shutdown ssl\n");
|
||||
SSL_shutdown(session->ssl);
|
||||
SSL_free(session->ssl);
|
||||
}
|
||||
|
||||
if(session->ctx) SSL_CTX_free(session->ctx);
|
||||
|
||||
free(session);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void p_clean_exit(){
|
||||
int i;
|
||||
|
||||
if(listenerfd != -1) close(listenerfd);
|
||||
|
||||
for(i=1; i<numfds; i++){
|
||||
close(poll_set[i].fd);
|
||||
free_smtp_session(sessions[i]);
|
||||
}
|
||||
|
||||
syslog(LOG_PRIORITY, "%s has been terminated", PROGNAME);
|
||||
|
||||
//unlink(cfg.pidfile);
|
||||
|
||||
ERR_free_strings();
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
void fatal(char *s){
|
||||
syslog(LOG_PRIORITY, "%s", s);
|
||||
p_clean_exit();
|
||||
}
|
||||
|
||||
|
||||
void tear_down_client(int n){
|
||||
int i;
|
||||
|
||||
close(poll_set[n].fd);
|
||||
poll_set[n].events = 0;
|
||||
|
||||
syslog(LOG_PRIORITY, "disconnected from %s", sessions[n]->remote_host);
|
||||
|
||||
// new code
|
||||
free_smtp_session(sessions[n]);
|
||||
sessions[n] = NULL;
|
||||
|
||||
for(i=n; i<numfds; i++){
|
||||
poll_set[i] = poll_set[i+1];
|
||||
sessions[i] = sessions[i+1];
|
||||
}
|
||||
|
||||
numfds--;
|
||||
}
|
||||
|
||||
|
||||
void check_for_client_timeout(){
|
||||
time_t now;
|
||||
int i;
|
||||
|
||||
if(numfds > 1){
|
||||
time(&now);
|
||||
|
||||
for(i=1; i<numfds; i++){
|
||||
if(now - sessions[i]->lasttime >= cfg.smtp_timeout){
|
||||
syslog(LOG_PRIORITY, "client %s timeout", sessions[i]->remote_host);
|
||||
tear_down_client(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
alarm(timeout);
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_LIBWRAP
|
||||
int is_blocked_by_tcp_wrappers(int sd){
|
||||
struct request_info req;
|
||||
|
||||
request_init(&req, RQ_DAEMON, PROGNAME, RQ_FILE, sd, 0);
|
||||
|
||||
fromhost(&req);
|
||||
|
||||
if(!hosts_access(&req)){
|
||||
send(sd, SMTP_RESP_550_ERR_YOU_ARE_BANNED_BY_LOCAL_POLICY, strlen(SMTP_RESP_550_ERR_YOU_ARE_BANNED_BY_LOCAL_POLICY), 0);
|
||||
syslog(LOG_PRIORITY, "denied connection from %s by tcp_wrappers", eval_client(&req));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int create_listener_socket(char *listen_addr, int listen_port){
|
||||
int rc, sd, yes=1;
|
||||
char port_string[8];
|
||||
struct addrinfo hints, *res;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
snprintf(port_string, sizeof(port_string)-1, "%d", listen_port);
|
||||
|
||||
if((rc = getaddrinfo(listen_addr, port_string, &hints, &res)) != 0){
|
||||
syslog(LOG_PRIORITY, "getaddrinfo for '%s': %s", listen_addr, gai_strerror(rc));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if((sd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1){
|
||||
syslog(LOG_PRIORITY, "socket() error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){
|
||||
syslog(LOG_PRIORITY, "setsockopt() error");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(ioctl(sd, FIONBIO, (char *)&yes) == -1){
|
||||
syslog(LOG_PRIORITY, "ioctl() failed");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(bind(sd, res->ai_addr, res->ai_addrlen) == -1){
|
||||
syslog(LOG_PRIORITY, "cannot bind to port: %s:%d", listen_addr, listen_port);
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
freeaddrinfo(res);
|
||||
|
||||
if(listen(sd, cfg.backlog) == -1){
|
||||
syslog(LOG_PRIORITY, "listen() error");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sd;
|
||||
}
|
||||
|
||||
|
||||
void start_new_session(int socket, struct sockaddr_storage client_address, int fd_index){
|
||||
char smtp_banner[SMALLBUFSIZE], remote_host[INET6_ADDRSTRLEN];
|
||||
|
||||
// Uh-oh! We have enough connections to serve already
|
||||
if(numfds >= POLL_SIZE){
|
||||
inet_ntop(client_address.ss_family, get_in_addr((struct sockaddr*)&client_address), remote_host, sizeof(remote_host));
|
||||
syslog(LOG_PRIORITY, "too many connections (%d), cannot accept %s", numfds, remote_host);
|
||||
send(socket, SMTP_RESP_421_ERR_ALL_PORTS_ARE_BUSY, strlen(SMTP_RESP_421_ERR_ALL_PORTS_ARE_BUSY), 0);
|
||||
close(socket);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBWRAP
|
||||
if(is_blocked_by_tcp_wrappers(socket) == 1){
|
||||
close(socket);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
sessions[numfds] = malloc(sizeof(struct smtp_session));
|
||||
|
||||
if(sessions[numfds] == NULL){
|
||||
syslog(LOG_PRIORITY, "malloc error()");
|
||||
send(socket, SMTP_RESP_421_ERR_TMP, strlen(SMTP_RESP_421_ERR_TMP), 0);
|
||||
close(socket);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
init_smtp_session(sessions[numfds], fd_index, socket);
|
||||
|
||||
snprintf(smtp_banner, sizeof(smtp_banner)-1, SMTP_RESP_220_BANNER, cfg.hostid);
|
||||
send(socket, smtp_banner, strlen(smtp_banner), 0);
|
||||
|
||||
inet_ntop(client_address.ss_family, get_in_addr((struct sockaddr*)&client_address), sessions[numfds]->remote_host, INET6_ADDRSTRLEN);
|
||||
|
||||
syslog(LOG_PRIORITY, "connected from %s", sessions[numfds]->remote_host);
|
||||
|
||||
poll_set[numfds].fd = socket;
|
||||
poll_set[numfds].events = POLLIN|POLLHUP;
|
||||
|
||||
numfds++;
|
||||
}
|
||||
|
||||
|
||||
void initialise_configuration(){
|
||||
cfg = read_config(configfile);
|
||||
|
||||
if(strlen(cfg.username) > 1){
|
||||
pwd = getpwnam(cfg.username);
|
||||
if(!pwd) fatal(ERR_NON_EXISTENT_USER);
|
||||
}
|
||||
|
||||
if(getuid() == 0 && pwd){
|
||||
check_and_create_directories(&cfg, pwd->pw_uid, pwd->pw_gid);
|
||||
}
|
||||
|
||||
if(chdir(cfg.workdir)){
|
||||
syslog(LOG_PRIORITY, "workdir: *%s*", cfg.workdir);
|
||||
fatal(ERR_CHDIR);
|
||||
}
|
||||
|
||||
setlocale(LC_MESSAGES, cfg.locale);
|
||||
setlocale(LC_CTYPE, cfg.locale);
|
||||
|
||||
syslog(LOG_PRIORITY, "reloaded config: %s", configfile);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv){
|
||||
int listenerfd, client_sockfd;
|
||||
int i, daemonise=0;
|
||||
int client_len = sizeof(struct sockaddr_storage);
|
||||
int readlen;
|
||||
int bytes_to_read;
|
||||
struct sockaddr_storage client_address;
|
||||
char readbuf[BIGBUFSIZE];
|
||||
|
||||
while((i = getopt(argc, argv, "c:dvVh")) > 0){
|
||||
switch(i){
|
||||
|
||||
case 'c' :
|
||||
configfile = optarg;
|
||||
break;
|
||||
|
||||
case 'd' :
|
||||
daemonise = 1;
|
||||
break;
|
||||
|
||||
case 'v' :
|
||||
case 'V' :
|
||||
printf("%s build %d\n", VERSION, get_build());
|
||||
return 0;
|
||||
|
||||
case 'h' :
|
||||
default :
|
||||
__fatal("usage: ...");
|
||||
}
|
||||
}
|
||||
|
||||
(void) openlog("piler-poll", LOG_PID, LOG_MAIL);
|
||||
|
||||
memset(sessions, '\0', sizeof(sessions));
|
||||
memset(poll_set, '\0', sizeof(poll_set));
|
||||
|
||||
initialise_configuration();
|
||||
|
||||
listenerfd = create_listener_socket(cfg.listen_addr, cfg.listen_port);
|
||||
if(listenerfd == -1){
|
||||
syslog(LOG_PRIORITY, "create_listener_socket() error");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(drop_privileges(pwd)) fatal(ERR_SETUID);
|
||||
|
||||
set_signal_handler(SIGTERM, p_clean_exit);
|
||||
set_signal_handler(SIGALRM, check_for_client_timeout);
|
||||
set_signal_handler(SIGHUP, initialise_configuration);
|
||||
|
||||
alarm(timeout);
|
||||
|
||||
poll_set[0].fd = listenerfd;
|
||||
poll_set[0].events = POLLIN;
|
||||
numfds = 1;
|
||||
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
|
||||
srand(getpid());
|
||||
|
||||
#if HAVE_DAEMON == 1
|
||||
if(daemonise == 1 && daemon(1, 0) == -1) fatal(ERR_DAEMON);
|
||||
#endif
|
||||
|
||||
for(;;){
|
||||
int fd_index;
|
||||
|
||||
poll(poll_set, numfds, -1);
|
||||
|
||||
for(fd_index = 0; fd_index < numfds; fd_index++){
|
||||
if(poll_set[fd_index].revents & POLLIN){
|
||||
|
||||
// process new connection
|
||||
|
||||
if(poll_set[fd_index].fd == listenerfd){
|
||||
client_sockfd = accept(listenerfd, (struct sockaddr *)&client_address, (socklen_t *)&client_len);
|
||||
start_new_session(client_sockfd, client_address, fd_index);
|
||||
}
|
||||
|
||||
// handle data from an existing connection
|
||||
|
||||
else {
|
||||
ioctl(poll_set[fd_index].fd, FIONREAD, &bytes_to_read);
|
||||
|
||||
if(cfg.verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "got %d bytes to read", bytes_to_read);
|
||||
|
||||
if(bytes_to_read == 0){
|
||||
tear_down_client(fd_index);
|
||||
}
|
||||
else {
|
||||
session = sessions[fd_index];
|
||||
|
||||
time(&(session->lasttime));
|
||||
|
||||
// readbuf must be large enough to hold 'bytes_to_read' data
|
||||
// I think there shouldn't be more than MTU size data to be
|
||||
// read from the socket at a time
|
||||
memset(readbuf, 0, sizeof(readbuf));
|
||||
|
||||
if(session->use_ssl == 1)
|
||||
readlen = SSL_read(session->ssl, (char*)&readbuf[0], sizeof(readbuf)-1);
|
||||
else
|
||||
readlen = recv(poll_set[fd_index].fd, &readbuf[0], sizeof(readbuf)-1, 0);
|
||||
|
||||
if(readlen < 1) break;
|
||||
|
||||
readbuf[readlen] = '\0'; // we need either this or memset(readbuf, ...) above
|
||||
|
||||
handle_data(session, &readbuf[0], readlen);
|
||||
|
||||
if(session->protocol_state == SMTP_STATE_BDAT && session->bad == 1) tear_down_client(fd_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
67
src/piler.c
67
src/piler.c
@ -102,16 +102,24 @@ static void child_sighup_handler(int sig){
|
||||
|
||||
|
||||
static void child_main(struct child *ptr){
|
||||
char s[INET6_ADDRSTRLEN];
|
||||
struct sockaddr_storage client_addr;
|
||||
socklen_t addr_size;
|
||||
struct session_ctx sctx;
|
||||
struct import import;
|
||||
struct session_data sdata;
|
||||
int tot_msgs = 0;
|
||||
char dir[TINYBUFSIZE];
|
||||
|
||||
/* open directory, then process its files, then sleep 2 sec, and repeat */
|
||||
|
||||
import.total_messages = import.total_size = import.processed_messages = import.batch_processing_limit = 0;
|
||||
import.remove_after_import = 1;
|
||||
import.extra_recipient = import.move_folder = NULL;
|
||||
|
||||
data.import = &import;
|
||||
|
||||
ptr->messages = 0;
|
||||
sctx.data = &data;
|
||||
sctx.cfg = &cfg;
|
||||
|
||||
if(cfg.verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "child (pid: %d, serial: %d) started main()", getpid(), ptr->serial);
|
||||
snprintf(dir, sizeof(dir)-1, "%d", ptr->serial);
|
||||
|
||||
if(cfg.verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "child (pid: %d, serial: %d) started main() working on '%s'", getpid(), ptr->serial, dir);
|
||||
|
||||
while(1){
|
||||
if(received_sighup == 1){
|
||||
@ -119,35 +127,30 @@ static void child_main(struct child *ptr){
|
||||
break;
|
||||
}
|
||||
|
||||
ptr->status = READY;
|
||||
|
||||
addr_size = sizeof(client_addr);
|
||||
sctx.new_sd = accept(sd, (struct sockaddr *)&client_addr, &addr_size);
|
||||
|
||||
if(sctx.new_sd == -1) continue;
|
||||
|
||||
ptr->status = BUSY;
|
||||
|
||||
inet_ntop(client_addr.ss_family, get_in_addr((struct sockaddr *)&client_addr), s, sizeof(s)-1);
|
||||
|
||||
syslog(LOG_PRIORITY, "connection from %s", s);
|
||||
|
||||
data.child_serial = ptr->serial;
|
||||
|
||||
sig_block(SIGHUP);
|
||||
ptr->messages += handle_smtp_session(&sctx);
|
||||
sig_unblock(SIGHUP);
|
||||
|
||||
close(sctx.new_sd);
|
||||
if(open_database(&sdata, &cfg) == OK){
|
||||
import_from_maildir(dir, &sdata, &data, &tot_msgs, &cfg);
|
||||
ptr->messages += tot_msgs;
|
||||
close_database(&sdata);
|
||||
|
||||
if(cfg.max_requests_per_child > 0 && ptr->messages >= cfg.max_requests_per_child){
|
||||
if(cfg.verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "child (pid: %d, serial: %d) served enough: %d", getpid(), ptr->messages, ptr->serial);
|
||||
break;
|
||||
sleep(2);
|
||||
}
|
||||
else {
|
||||
syslog(LOG_PRIORITY, "ERROR: cannot open database");
|
||||
sleep(10);
|
||||
}
|
||||
|
||||
}
|
||||
sig_unblock(SIGHUP);
|
||||
|
||||
ptr->status = UNDEF;
|
||||
// TODO: do we want to quit after processing a certain number of messages?
|
||||
|
||||
//if(cfg.max_requests_per_child > 0 && ptr->messages >= cfg.max_requests_per_child){
|
||||
// if(cfg.verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "child (pid: %d, serial: %d) served enough: %d", getpid(), ptr->messages, ptr->serial);
|
||||
// break;
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
#ifdef HAVE_MEMCACHED
|
||||
memcached_shutdown(&(data.memc));
|
||||
@ -409,7 +412,8 @@ int main(int argc, char **argv){
|
||||
|
||||
snprintf(port_string, sizeof(port_string)-1, "%d", cfg.listen_port);
|
||||
|
||||
if((rc = getaddrinfo(cfg.listen_addr, port_string, &hints, &res)) != 0){
|
||||
//if((rc = getaddrinfo(cfg.listen_addr, port_string, &hints, &res)) != 0){
|
||||
if((rc = getaddrinfo("127.0.0.1", "5678", &hints, &res)) != 0){
|
||||
fprintf(stderr, "getaddrinfo for '%s': %s\n", cfg.listen_addr, gai_strerror(rc));
|
||||
return 1;
|
||||
}
|
||||
@ -466,4 +470,3 @@ int main(int argc, char **argv){
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <rules.h>
|
||||
#include <sql.h>
|
||||
#include <import.h>
|
||||
#include <smtp.h>
|
||||
#include <config.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@ -29,6 +30,8 @@
|
||||
int read_key(struct __config *cfg);
|
||||
void insert_offset(struct session_data *sdata, int server_id);
|
||||
|
||||
void tear_down_client(int n);
|
||||
|
||||
int do_av_check(struct session_data *sdata, char *virusinfo, struct __data *data, struct __config *cfg);
|
||||
|
||||
int make_digests(struct session_data *sdata, struct __config *cfg);
|
||||
@ -69,7 +72,6 @@ int is_email_address_on_my_domains(char *email, struct __data *data);
|
||||
int is_blocked_by_tcp_wrappers(int sd);
|
||||
void send_response_to_data(struct session_ctx *sctx, char *rcptto);
|
||||
void process_written_file(struct session_ctx *sctx);
|
||||
void process_data(struct session_ctx *sctx);
|
||||
|
||||
#endif /* _PILER_H */
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
#ifndef _SIG_H
|
||||
#define _SIG_H
|
||||
|
||||
typedef void signal_func (int);
|
||||
|
||||
void sig_block(int sig);
|
||||
void sig_unblock(int sig);
|
||||
void sig_catch(int sig, void (*f)());
|
||||
|
458
src/smtp.c
458
src/smtp.c
@ -1,285 +1,319 @@
|
||||
/*
|
||||
* smtp.c, SJ
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <piler.h>
|
||||
#include <smtp.h>
|
||||
#include "smtp.h"
|
||||
|
||||
|
||||
void process_command_ehlo_lhlo(struct session_ctx *sctx, int *protocol_state, char *resp, int resplen){
|
||||
char tmpbuf[MAXBUFSIZE];
|
||||
void process_smtp_command(struct smtp_session *session, char *buf){
|
||||
char response[SMALLBUFSIZE];
|
||||
|
||||
if(session->cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "processing command: *%s*", buf);
|
||||
|
||||
if(strncasecmp(buf, SMTP_CMD_HELO, strlen(SMTP_CMD_HELO)) == 0){
|
||||
process_command_helo(session, response, sizeof(response));
|
||||
return;
|
||||
}
|
||||
|
||||
if(strncasecmp(buf, SMTP_CMD_EHLO, strlen(SMTP_CMD_EHLO)) == 0 ||
|
||||
strncasecmp(buf, LMTP_CMD_LHLO, strlen(LMTP_CMD_LHLO)) == 0){
|
||||
process_command_ehlo_lhlo(session, response, sizeof(response));
|
||||
return;
|
||||
}
|
||||
|
||||
if(strncasecmp(buf, SMTP_CMD_MAIL_FROM, strlen(SMTP_CMD_MAIL_FROM)) == 0){
|
||||
process_command_mail_from(session, buf);
|
||||
return;
|
||||
}
|
||||
|
||||
if(strncasecmp(buf, SMTP_CMD_RCPT_TO, strlen(SMTP_CMD_RCPT_TO)) == 0){
|
||||
process_command_rcpt_to(session, buf);
|
||||
return;
|
||||
}
|
||||
|
||||
if(strncasecmp(buf, SMTP_CMD_DATA, strlen(SMTP_CMD_DATA)) == 0){
|
||||
process_command_data(session);
|
||||
return;
|
||||
}
|
||||
|
||||
if(session->cfg->enable_chunking == 1 && strncasecmp(buf, SMTP_CMD_BDAT, strlen(SMTP_CMD_BDAT)) == 0){
|
||||
get_bdat_size_to_read(session, buf);
|
||||
return;
|
||||
}
|
||||
|
||||
if(strncasecmp(buf, SMTP_CMD_QUIT, strlen(SMTP_CMD_QUIT)) == 0){
|
||||
process_command_quit(session, response, sizeof(response));
|
||||
return;
|
||||
}
|
||||
|
||||
if(strncasecmp(buf, SMTP_CMD_RESET, strlen(SMTP_CMD_RESET)) == 0){
|
||||
process_command_reset(session);
|
||||
return;
|
||||
}
|
||||
|
||||
if(session->cfg->tls_enable == 1 && strncasecmp(buf, SMTP_CMD_STARTTLS, strlen(SMTP_CMD_STARTTLS)) == 0 && session->use_ssl == 0){
|
||||
process_command_starttls(session);
|
||||
return;
|
||||
}
|
||||
|
||||
send_smtp_response(session, SMTP_RESP_502_ERR);
|
||||
}
|
||||
|
||||
|
||||
void process_data(struct smtp_session *session, char *readbuf, int readlen){
|
||||
char puf[SMALLBUFSIZE+BIGBUFSIZE];
|
||||
int n, pos, len;
|
||||
|
||||
memset(puf, 0, sizeof(puf));
|
||||
|
||||
if(session->buflen > 0){
|
||||
memcpy(&puf[0], session->buf, session->buflen);
|
||||
memcpy(&puf[session->buflen], readbuf, readlen);
|
||||
len = session->buflen + readlen;
|
||||
}
|
||||
else {
|
||||
memcpy(&puf[0], readbuf, readlen);
|
||||
len = readlen;
|
||||
}
|
||||
|
||||
pos = searchStringInBuffer(&puf[0], len, SMTP_CMD_PERIOD, 5);
|
||||
|
||||
if(pos > 0){
|
||||
//write(session->fd, puf, pos+2);
|
||||
//session->tot_len += pos+2;
|
||||
write(session->fd, puf, pos);
|
||||
session->tot_len += pos;
|
||||
process_command_period(session);
|
||||
}
|
||||
else {
|
||||
n = search_char_backward(&puf[0], len, '\r');
|
||||
|
||||
if(n == -1 || len - n > 4){
|
||||
write(session->fd, puf, len);
|
||||
session->tot_len += len;
|
||||
}
|
||||
else {
|
||||
write(session->fd, puf, n);
|
||||
session->tot_len += n;
|
||||
|
||||
snprintf(session->buf, SMALLBUFSIZE-1, "%s", &puf[n]);
|
||||
session->buflen = len - n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void send_smtp_response(struct smtp_session *session, char *buf){
|
||||
int rc;
|
||||
char ssl_error[SMALLBUFSIZE];
|
||||
|
||||
write1(session->socket, buf, strlen(buf), session->use_ssl, session->ssl);
|
||||
|
||||
if(session->cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "sent: %s", buf);
|
||||
|
||||
if(session->starttls == 1 && session->use_ssl == 0){
|
||||
|
||||
if(session->cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "waiting for ssl handshake");
|
||||
|
||||
rc = SSL_accept(session->ssl);
|
||||
|
||||
if(session->cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "SSL_accept() finished");
|
||||
|
||||
if(rc == 1){
|
||||
session->use_ssl = 1;
|
||||
}
|
||||
else {
|
||||
ERR_error_string_n(ERR_get_error(), ssl_error, SMALLBUFSIZE);
|
||||
syslog(LOG_PRIORITY, "%s: SSL_accept() failed, rc=%d, errorcode: %d, error text: %s\n", session->ttmpfile, rc, SSL_get_error(session->ssl, rc), ssl_error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void process_command_helo(struct smtp_session *session, char *buf, int buflen){
|
||||
if(session->protocol_state == SMTP_STATE_INIT) session->protocol_state = SMTP_STATE_HELO;
|
||||
|
||||
snprintf(buf, buflen-1, "220 %s ESMTP\r\n", session->cfg->hostid);
|
||||
send_smtp_response(session, buf);
|
||||
}
|
||||
|
||||
|
||||
void process_command_ehlo_lhlo(struct smtp_session *session, char *buf, int buflen){
|
||||
char extensions[SMALLBUFSIZE];
|
||||
|
||||
memset(extensions, 0, sizeof(extensions));
|
||||
|
||||
if(*protocol_state == SMTP_STATE_INIT) *protocol_state = SMTP_STATE_HELO;
|
||||
if(session->protocol_state == SMTP_STATE_INIT) session->protocol_state = SMTP_STATE_HELO;
|
||||
|
||||
if(sctx->sdata->tls == 0) snprintf(extensions, sizeof(extensions)-1, "%s", sctx->data->starttls);
|
||||
if(sctx->cfg->enable_chunking == 1) strncat(extensions, SMTP_EXTENSION_CHUNKING, sizeof(extensions)-strlen(extensions)-2);
|
||||
// if tls is not started, but it's enabled in the config
|
||||
if(session->use_ssl == 0 && session->cfg->tls_enable == 1) snprintf(extensions, sizeof(extensions)-1, "%s", SMTP_EXTENSION_STARTTLS);
|
||||
if(session->cfg->enable_chunking == 1) strncat(extensions, SMTP_EXTENSION_CHUNKING, sizeof(extensions)-strlen(extensions)-2);
|
||||
|
||||
snprintf(tmpbuf, sizeof(tmpbuf)-1, SMTP_RESP_250_EXTENSIONS, sctx->cfg->hostid, extensions);
|
||||
snprintf(buf, buflen-1, SMTP_RESP_250_EXTENSIONS, session->cfg->hostid, extensions);
|
||||
|
||||
strncat(resp, tmpbuf, resplen-strlen(resp));
|
||||
send_smtp_response(session, buf);
|
||||
}
|
||||
|
||||
|
||||
void process_command_starttls(struct session_ctx *sctx, int *protocol_state, int *starttls, char *resp, int resplen){
|
||||
int init_ssl(struct smtp_session *session){
|
||||
session->ctx = SSL_CTX_new(TLSv1_server_method());
|
||||
|
||||
if(sctx->cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: starttls request from client", sctx->sdata->ttmpfile);
|
||||
if(session->ctx == NULL){
|
||||
syslog(LOG_PRIORITY, "%s: SSL ctx is null!", session->ttmpfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(sctx->data->ctx){
|
||||
sctx->data->ssl = SSL_new(sctx->data->ctx);
|
||||
if(sctx->data->ssl){
|
||||
if(SSL_CTX_set_cipher_list(session->ctx, session->cfg->cipher_list) == 0){
|
||||
syslog(LOG_PRIORITY, "failed to set cipher list: '%s'", session->cfg->cipher_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SSL_set_options(sctx->data->ssl, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3);
|
||||
if(SSL_CTX_use_PrivateKey_file(session->ctx, session->cfg->pemfile, SSL_FILETYPE_PEM) != 1){
|
||||
syslog(LOG_PRIORITY, "cannot load private key from %s", session->cfg->pemfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(SSL_set_fd(sctx->data->ssl, sctx->new_sd) == 1){
|
||||
strncat(resp, SMTP_RESP_220_READY_TO_START_TLS, resplen);
|
||||
*starttls = 1;
|
||||
*protocol_state = SMTP_STATE_INIT;
|
||||
if(SSL_CTX_use_certificate_file(session->ctx, session->cfg->pemfile, SSL_FILETYPE_PEM) != 1){
|
||||
syslog(LOG_PRIORITY, "cannot load certificate from %s", session->cfg->pemfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void process_command_starttls(struct smtp_session *session){
|
||||
if(session->cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "starttls request from client");
|
||||
|
||||
if(init_ssl(session) == 1){
|
||||
|
||||
session->ssl = SSL_new(session->ctx);
|
||||
if(session->ssl){
|
||||
|
||||
SSL_set_options(session->ssl, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3);
|
||||
|
||||
if(SSL_set_fd(session->ssl, session->socket) == 1){
|
||||
session->starttls = 1;
|
||||
send_smtp_response(session, SMTP_RESP_220_READY_TO_START_TLS);
|
||||
session->protocol_state = SMTP_STATE_INIT;
|
||||
session->use_ssl = 1;
|
||||
return;
|
||||
} syslog(LOG_PRIORITY, "%s: SSL_set_fd() failed", sctx->sdata->ttmpfile);
|
||||
} syslog(LOG_PRIORITY, "%s: SSL_new() failed", sctx->sdata->ttmpfile);
|
||||
} syslog(LOG_PRIORITY, "%s: SSL ctx is null!", sctx->sdata->ttmpfile);
|
||||
} syslog(LOG_PRIORITY, "%s: SSL_set_fd() failed", session->ttmpfile);
|
||||
} syslog(LOG_PRIORITY, "%s: SSL_new() failed", session->ttmpfile);
|
||||
} syslog(LOG_PRIORITY, "%s: SSL ctx is null!", session->ttmpfile);
|
||||
|
||||
strncat(resp, SMTP_RESP_454_ERR_TLS_TEMP_ERROR, resplen);
|
||||
send_smtp_response(session, SMTP_RESP_454_ERR_TLS_TEMP_ERROR);
|
||||
}
|
||||
|
||||
|
||||
void process_command_mail_from(struct session_ctx *sctx, int *protocol_state, char *buf, char *resp, int resplen){
|
||||
void process_command_mail_from(struct smtp_session *session, char *buf){
|
||||
memset(session->mailfrom, 0, SMALLBUFSIZE);
|
||||
|
||||
if(*protocol_state != SMTP_STATE_HELO && *protocol_state != SMTP_STATE_PERIOD && *protocol_state != SMTP_STATE_BDAT){
|
||||
strncat(resp, SMTP_RESP_503_ERR, resplen);
|
||||
if(session->protocol_state != SMTP_STATE_HELO && session->protocol_state != SMTP_STATE_PERIOD && session->protocol_state != SMTP_STATE_BDAT){
|
||||
send(session->socket, SMTP_RESP_503_ERR, strlen(SMTP_RESP_503_ERR), 0);
|
||||
}
|
||||
else {
|
||||
if(*protocol_state == SMTP_STATE_PERIOD || *protocol_state == SMTP_STATE_BDAT){
|
||||
if(sctx->cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: initiated new transaction", sctx->sdata->ttmpfile);
|
||||
create_id(&(session->ttmpfile[0]), 15);
|
||||
session->protocol_state = SMTP_STATE_MAIL_FROM;
|
||||
|
||||
unlink(sctx->sdata->ttmpfile);
|
||||
unlink(sctx->sdata->tmpframe);
|
||||
extractEmail(buf, session->mailfrom);
|
||||
|
||||
init_session_data(sctx->sdata, sctx->cfg);
|
||||
}
|
||||
reset_bdat_counters(session);
|
||||
session->tot_len = 0;
|
||||
|
||||
*protocol_state = SMTP_STATE_MAIL_FROM;
|
||||
|
||||
snprintf(sctx->sdata->mailfrom, SMALLBUFSIZE-1, "%s\r\n", buf);
|
||||
|
||||
memset(sctx->sdata->fromemail, 0, SMALLBUFSIZE);
|
||||
extractEmail(sctx->sdata->mailfrom, sctx->sdata->fromemail);
|
||||
|
||||
strncat(resp, SMTP_RESP_250_OK, strlen(SMTP_RESP_250_OK));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void process_command_rcpt_to(struct session_ctx *sctx, int *protocol_state, char *buf, char *resp, int resplen){
|
||||
|
||||
if(*protocol_state == SMTP_STATE_MAIL_FROM || *protocol_state == SMTP_STATE_RCPT_TO){
|
||||
|
||||
if(strlen(buf) > SMALLBUFSIZE/2){
|
||||
strncat(resp, SMTP_RESP_550_ERR_TOO_LONG_RCPT_TO, resplen);
|
||||
return;
|
||||
}
|
||||
|
||||
if(sctx->sdata->num_of_rcpt_to < MAX_RCPT_TO-1){
|
||||
extractEmail(buf, sctx->sdata->rcptto[sctx->sdata->num_of_rcpt_to]);
|
||||
}
|
||||
|
||||
*protocol_state = SMTP_STATE_RCPT_TO;
|
||||
|
||||
if(sctx->sdata->num_of_rcpt_to < MAX_RCPT_TO-1) sctx->sdata->num_of_rcpt_to++;
|
||||
|
||||
strncat(resp, SMTP_RESP_250_OK, resplen);
|
||||
}
|
||||
else {
|
||||
strncat(resp, SMTP_RESP_503_ERR, resplen);
|
||||
send_smtp_response(session, SMTP_RESP_250_OK);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void process_command_data(struct session_ctx *sctx, int *protocol_state, char *resp, int resplen){
|
||||
void process_command_rcpt_to(struct smtp_session *session, char *buf){
|
||||
|
||||
if(*protocol_state != SMTP_STATE_RCPT_TO){
|
||||
strncat(resp, SMTP_RESP_503_ERR, resplen);
|
||||
if(session->protocol_state == SMTP_STATE_MAIL_FROM || session->protocol_state == SMTP_STATE_RCPT_TO){
|
||||
|
||||
// For now, we are not interested in the envelope recipients
|
||||
|
||||
session->protocol_state = SMTP_STATE_RCPT_TO;
|
||||
send_smtp_response(session, SMTP_RESP_250_OK);
|
||||
}
|
||||
else {
|
||||
sctx->sdata->fd = open(sctx->sdata->filename, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP);
|
||||
if(sctx->sdata->fd == -1){
|
||||
syslog(LOG_PRIORITY, "%s: %s", ERR_OPEN_TMP_FILE, sctx->sdata->ttmpfile);
|
||||
strncat(resp, SMTP_RESP_451_ERR, resplen);
|
||||
send_smtp_response(session, SMTP_RESP_503_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void process_command_data(struct smtp_session *session){
|
||||
session->tot_len = 0;
|
||||
|
||||
if(session->protocol_state != SMTP_STATE_RCPT_TO){
|
||||
send_smtp_response(session, SMTP_RESP_503_ERR);
|
||||
}
|
||||
else {
|
||||
session->fd = open(session->ttmpfile, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP);
|
||||
if(session->fd == -1){
|
||||
syslog(LOG_PRIORITY, "%s: %s", ERR_OPEN_TMP_FILE, session->ttmpfile);
|
||||
send_smtp_response(session, SMTP_RESP_451_ERR);
|
||||
}
|
||||
else {
|
||||
*protocol_state = SMTP_STATE_DATA;
|
||||
strncat(resp, SMTP_RESP_354_DATA_OK, resplen-1);
|
||||
session->protocol_state = SMTP_STATE_DATA;
|
||||
send_smtp_response(session, SMTP_RESP_354_DATA_OK);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void process_command_period(struct smtp_session *session){
|
||||
char buf[SMALLBUFSIZE];
|
||||
|
||||
void process_command_bdat(struct session_ctx *sctx, int *protocol_state, char *buf, char *resp, int resplen){
|
||||
int n, expected_bdat_len;
|
||||
char puf[MAXBUFSIZE];
|
||||
session->protocol_state = SMTP_STATE_PERIOD;
|
||||
|
||||
if(*protocol_state != SMTP_STATE_RCPT_TO){
|
||||
strncat(resp, SMTP_RESP_503_ERR, resplen);
|
||||
return;
|
||||
}
|
||||
// TODO: add some error handling
|
||||
|
||||
sctx->bdat_rounds = 0;
|
||||
sctx->bdat_last_round = 0;
|
||||
fsync(session->fd);
|
||||
close(session->fd);
|
||||
|
||||
while(sctx->bdat_last_round != 1){
|
||||
sctx->bdat_rounds++;
|
||||
expected_bdat_len = 0;
|
||||
session->fd = -1;
|
||||
|
||||
if(sctx->bdat_rounds == 1){
|
||||
expected_bdat_len = extract_bdat_command(sctx, buf);
|
||||
syslog(LOG_PRIORITY, "received: %s, from=%s, size=%d", session->ttmpfile, session->mailfrom, session->tot_len);
|
||||
|
||||
sctx->sdata->fd = open(sctx->sdata->filename, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP);
|
||||
if(sctx->sdata->fd == -1){
|
||||
syslog(LOG_PRIORITY, "%s: %s", ERR_OPEN_TMP_FILE, sctx->sdata->ttmpfile);
|
||||
strncat(resp, SMTP_RESP_451_ERR, resplen);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
*protocol_state = SMTP_STATE_BDAT;
|
||||
}
|
||||
}
|
||||
else if(sctx->bdat_last_round != 1){
|
||||
if((n = recvtimeoutssl(sctx->new_sd, &puf[0], sizeof(puf), TIMEOUT, sctx->sdata->tls, sctx->data->ssl)) > 0){
|
||||
expected_bdat_len = extract_bdat_command(sctx, puf);
|
||||
if(expected_bdat_len <= 0 && sctx->bdat_rounds > 0) sctx->bdat_rounds--;
|
||||
}
|
||||
}
|
||||
move_email(session);
|
||||
|
||||
if(expected_bdat_len > 0) sctx->sdata->tot_len += read_bdat_data(sctx, expected_bdat_len);
|
||||
}
|
||||
snprintf(buf, sizeof(buf)-1, "250 OK <%s>\r\n", session->ttmpfile);
|
||||
|
||||
fsync(sctx->sdata->fd);
|
||||
close(sctx->sdata->fd);
|
||||
session->buflen = 0;
|
||||
memset(session->buf, 0, SMALLBUFSIZE);
|
||||
|
||||
send_smtp_response(session, buf);
|
||||
}
|
||||
|
||||
|
||||
int extract_bdat_command(struct session_ctx *sctx, char *buf){
|
||||
int expected_bdat_len=0;
|
||||
char *p;
|
||||
void process_command_quit(struct smtp_session *session, char *buf, int buflen){
|
||||
session->protocol_state = SMTP_STATE_FINISHED;
|
||||
|
||||
// determine if this is the last BDAT command
|
||||
snprintf(buf, buflen-1, SMTP_RESP_221_GOODBYE, session->cfg->hostid);
|
||||
|
||||
p = strcasestr(buf, " LAST");
|
||||
if(p){
|
||||
sctx->bdat_last_round = 1;
|
||||
syslog(LOG_INFO, "%s: BDAT LAST", sctx->sdata->ttmpfile);
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
// determine the size to be read
|
||||
|
||||
p = strchr(buf, ' ');
|
||||
if(p){
|
||||
expected_bdat_len = atoi(p);
|
||||
if(sctx->cfg->verbosity >= _LOG_DEBUG) syslog(LOG_INFO, "%s: BDAT len=%d", sctx->sdata->ttmpfile, expected_bdat_len);
|
||||
}
|
||||
|
||||
if(!p || expected_bdat_len <= 0){
|
||||
syslog(LOG_INFO, "%s: malformed BDAT command", sctx->sdata->ttmpfile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return expected_bdat_len;
|
||||
send_smtp_response(session, buf);
|
||||
}
|
||||
|
||||
|
||||
int read_bdat_data(struct session_ctx *sctx, int expected_bdat_len){
|
||||
int n, read_bdat_len=0, written_bdat_len=0;
|
||||
char puf[MAXBUFSIZE];
|
||||
void process_command_reset(struct smtp_session *session){
|
||||
send_smtp_response(session, SMTP_RESP_250_OK);
|
||||
|
||||
while(read_bdat_len < expected_bdat_len){
|
||||
if((n = recvtimeoutssl(sctx->new_sd, &puf[0], sizeof(puf), TIMEOUT, sctx->sdata->tls, sctx->data->ssl)) > 0){
|
||||
read_bdat_len += n;
|
||||
written_bdat_len += write(sctx->sdata->fd, puf, n);
|
||||
}
|
||||
}
|
||||
session->tot_len = 0;
|
||||
session->fd = -1;
|
||||
session->protocol_state = SMTP_STATE_HELO;
|
||||
|
||||
if(sctx->cfg->verbosity >= _LOG_DEBUG) syslog(LOG_INFO, "%s: wrote %d bytes of BDAT data", sctx->sdata->ttmpfile, written_bdat_len);
|
||||
reset_bdat_counters(session);
|
||||
|
||||
return written_bdat_len;
|
||||
create_id(&(session->ttmpfile[0]), 15);
|
||||
}
|
||||
|
||||
|
||||
void process_command_quit(struct session_ctx *sctx, int *protocol_state, char *resp, int resplen){
|
||||
char tmpbuf[MAXBUFSIZE];
|
||||
|
||||
*protocol_state = SMTP_STATE_FINISHED;
|
||||
|
||||
snprintf(tmpbuf, sizeof(tmpbuf)-1, SMTP_RESP_221_GOODBYE, sctx->cfg->hostid);
|
||||
strncat(resp, tmpbuf, resplen);
|
||||
|
||||
unlink(sctx->sdata->ttmpfile);
|
||||
unlink(sctx->sdata->tmpframe);
|
||||
|
||||
if(sctx->cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: removed", sctx->sdata->ttmpfile);
|
||||
}
|
||||
|
||||
|
||||
void process_command_reset(struct session_ctx *sctx, int *protocol_state, char *resp, int resplen){
|
||||
|
||||
strncat(resp, SMTP_RESP_250_OK, resplen);
|
||||
|
||||
if(sctx->cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: removed", sctx->sdata->ttmpfile);
|
||||
|
||||
unlink(sctx->sdata->ttmpfile);
|
||||
unlink(sctx->sdata->tmpframe);
|
||||
|
||||
init_session_data(sctx->sdata, sctx->cfg);
|
||||
|
||||
*protocol_state = SMTP_STATE_HELO;
|
||||
}
|
||||
|
||||
|
||||
void send_buffered_response(struct session_ctx *sctx, int starttls, char *resp){
|
||||
int rc;
|
||||
char ssl_error[SMALLBUFSIZE];
|
||||
|
||||
write1(sctx->new_sd, resp, strlen(resp), sctx->sdata->tls, sctx->data->ssl);
|
||||
|
||||
if(sctx->cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: sent: %s", sctx->sdata->ttmpfile, resp);
|
||||
memset(resp, 0, MAXBUFSIZE);
|
||||
|
||||
if(starttls == 1 && sctx->sdata->tls == 0){
|
||||
|
||||
if(sctx->cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: waiting for ssl handshake", sctx->sdata->ttmpfile);
|
||||
|
||||
rc = SSL_accept(sctx->data->ssl);
|
||||
|
||||
if(sctx->cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: SSL_accept() finished", sctx->sdata->ttmpfile);
|
||||
|
||||
if(rc == 1){
|
||||
sctx->sdata->tls = 1;
|
||||
}
|
||||
else {
|
||||
ERR_error_string_n(ERR_get_error(), ssl_error, SMALLBUFSIZE);
|
||||
syslog(LOG_PRIORITY, "%s: SSL_accept() failed, rc=%d, errorcode: %d, error text: %s\n", sctx->sdata->ttmpfile, rc, SSL_get_error(sctx->data->ssl, rc), ssl_error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
30
src/smtp.h
30
src/smtp.h
@ -5,18 +5,24 @@
|
||||
#ifndef _SMTP_H
|
||||
#define _SMTP_H
|
||||
|
||||
void process_command_ehlo_lhlo(struct session_ctx *sctx, int *protocol_state, char *resp, int resplen);
|
||||
void process_command_starttls(struct session_ctx *sctx, int *protocol_state, int *starttls, char *resp, int resplen);
|
||||
void process_command_mail_from(struct session_ctx *sctx, int *protocol_state, char *buf, char *resp, int resplen);
|
||||
void process_command_rcpt_to(struct session_ctx *sctx, int *protocol_state, char *buf, char *resp, int resplen);
|
||||
void process_command_data(struct session_ctx *sctx, int *protocol_state, char *resp, int resplen);
|
||||
void process_command_bdat(struct session_ctx *sctx, int *protocol_state, char *buf, char *resp, int resplen);
|
||||
void process_command_quit(struct session_ctx *sctx, int *protocol_state, char *resp, int resplen);
|
||||
void process_command_reset(struct session_ctx *sctx, int *protocol_state, char *resp, int resplen);
|
||||
#include <piler.h>
|
||||
|
||||
int read_bdat_data(struct session_ctx *sctx, int expected_bdat_len);
|
||||
int extract_bdat_command(struct session_ctx *sctx, char *buf);
|
||||
void process_smtp_command(struct smtp_session *session, char *buf);
|
||||
void process_data(struct smtp_session *session, char *readbuf, int readlen);
|
||||
|
||||
void send_buffered_response(struct session_ctx *sctx, int starttls, char *resp);
|
||||
void send_smtp_response(struct smtp_session *session, char *buf);
|
||||
void process_command_helo(struct smtp_session *session, char *buf, int buflen);
|
||||
void process_command_ehlo_lhlo(struct smtp_session *session, char *buf, int buflen);
|
||||
void process_command_quit(struct smtp_session *session, char *buf, int buflen);
|
||||
void process_command_reset(struct smtp_session *session);
|
||||
void process_command_mail_from(struct smtp_session *session, char *buf);
|
||||
void process_command_rcpt_to(struct smtp_session *session, char *buf);
|
||||
void process_command_data(struct smtp_session *session);
|
||||
void process_command_period(struct smtp_session *session);
|
||||
void process_command_starttls(struct smtp_session *session);
|
||||
|
||||
#endif /* _SMTP_H */
|
||||
void reset_bdat_counters(struct smtp_session *session);
|
||||
void get_bdat_size_to_read(struct smtp_session *session, char *buf);
|
||||
void process_bdat(struct smtp_session *session, char *readbuf, int readlen);
|
||||
|
||||
#endif
|
||||
|
@ -48,6 +48,7 @@
|
||||
#define SMTP_RESP_421_ERR "421 %s Error: timed out\r\n"
|
||||
#define SMTP_RESP_421_ERR_TMP "421 %s service not available\r\n"
|
||||
#define SMTP_RESP_421_ERR_WRITE_FAILED "421 writing queue file failed\r\n"
|
||||
#define SMTP_RESP_421_ERR_ALL_PORTS_ARE_BUSY "421 All server ports are busy\r\n"
|
||||
#define SMTP_RESP_450_ERR_CMD_NOT_IMPLEMENTED "450 command not implemented\r\n"
|
||||
#define SMTP_RESP_451_ERR "451 Error in processing, try again later\r\n"
|
||||
#define SMTP_RESP_454_ERR_TLS_TEMP_ERROR "454 TLS not available currently\r\n"
|
||||
@ -56,7 +57,6 @@
|
||||
#define SMTP_RESP_503_ERR "503 Bad command sequence\r\n"
|
||||
#define SMTP_RESP_530_ERR_MUST_ISSUE_STARTTLS_FIRST "530 MUST issue STARTTLS command first\r\n"
|
||||
#define SMTP_RESP_550_ERR "550 Access denied.\r\n"
|
||||
#define SMTP_RESP_550_ERR_PREF "550 Access denied."
|
||||
#define SMTP_RESP_550_INVALID_RECIPIENT "550 Unknown recipient\r\n"
|
||||
#define SMTP_RESP_550_ERR_TOO_LONG_RCPT_TO "550 too long recipient\r\n"
|
||||
#define SMTP_RESP_550_ERR_YOU_ARE_BANNED_BY_LOCAL_POLICY "550 You are banned by local policy\r\n"
|
||||
|
Loading…
Reference in New Issue
Block a user