mirror of
				https://bitbucket.org/jsuto/piler.git
				synced 2025-11-04 11:22:26 +01:00 
			
		
		
		
	first demo of the new architecture
Change-Id: Id76636f30173465fbd0e8516d99017b4336de4db Signed-off-by: SJ <sj@acts.hu>
This commit is contained in:
		
							
								
								
									
										4
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								configure
									
									
									
									
										vendored
									
									
								
							@@ -4645,7 +4645,7 @@ fi
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
if test "$os" = "FreeBSD"; then
 | 
					if test "$os" = "FreeBSD"; then
 | 
				
			||||||
   defs="$defs -DFREEBSD"
 | 
					   defs="$defs -DFREEBSD"
 | 
				
			||||||
   antispam_libs="-lz -lm -lcrypto -lssl"
 | 
					   antispam_libs="-lz -lm -lcrypto -lssl -liconv"
 | 
				
			||||||
   MAKE="gmake"
 | 
					   MAKE="gmake"
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -4866,7 +4866,7 @@ echo; echo
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
CFLAGS="$static -O2 -Wall -g"
 | 
					CFLAGS="$static -O2 -Wall -g"
 | 
				
			||||||
LIBS="$antispam_libs $sunos_libs "
 | 
					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"
 | 
					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"
 | 
					CFLAGS="$static -O2 -Wall -g"
 | 
				
			||||||
LIBS="$antispam_libs $sunos_libs "
 | 
					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_CONFIG_FILES([Makefile src/Makefile etc/Makefile util/Makefile init.d/Makefile unit_tests/Makefile contrib/imap/Makefile])
 | 
				
			||||||
AC_OUTPUT
 | 
					AC_OUTPUT
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,7 +33,7 @@ MAKE = `which make`
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
INSTALL = @INSTALL@
 | 
					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
 | 
					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
 | 
				
			||||||
	ln -sf libpiler.so.$(LIBPILER_VERSION) libpiler.so.$(PILER_VERSION)
 | 
						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
 | 
					pilerget: pilerget.c libpiler.a
 | 
				
			||||||
	$(CC) $(CFLAGS) $(INCDIR) $(DEFS) -o $@ $< -lpiler $(LIBS) $(LIBDIR)
 | 
						$(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))
 | 
						(cd $(DESTDIR)$(libdir) && ln -sf libpiler.so.$(LIBPILER_VERSION) libpiler.so.$(PILER_VERSION))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	$(INSTALL) -m 0755 piler $(DESTDIR)$(sbindir)
 | 
						$(INSTALL) -m 0755 piler $(DESTDIR)$(sbindir)
 | 
				
			||||||
 | 
						$(INSTALL) -m 0755 piler-smtp $(DESTDIR)$(sbindir)
 | 
				
			||||||
	$(INSTALL) -m 0755 pilerconf $(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) pilerget $(DESTDIR)$(bindir)
 | 
				
			||||||
	$(INSTALL) -m 6755 -o $(RUNNING_USER) -g $(RUNNING_GROUP) pileraget $(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)
 | 
						$(INSTALL) -m 6755 -o $(RUNNING_USER) -g $(RUNNING_GROUP) pilertest $(DESTDIR)$(bindir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
clean:
 | 
					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
 | 
					distclean: clean
 | 
				
			||||||
	rm -f Makefile
 | 
						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)},
 | 
					   { "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},
 | 
					   { "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)},
 | 
					   { "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},
 | 
					   { "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)},
 | 
					   { "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)},
 | 
					   { "tls_enable", "integer", (void*) int_parser, offsetof(struct __config, tls_enable), "0", sizeof(int)},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,6 +48,7 @@ struct __config {
 | 
				
			|||||||
   int verbosity;
 | 
					   int verbosity;
 | 
				
			||||||
   char locale[MAXVAL];
 | 
					   char locale[MAXVAL];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   int smtp_timeout;
 | 
				
			||||||
   int helper_timeout;
 | 
					   int helper_timeout;
 | 
				
			||||||
   int extract_attachments;
 | 
					   int extract_attachments;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,9 +11,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define PROGNAME "piler"
 | 
					#define PROGNAME "piler"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define VERSION "1.2.0"
 | 
					#define VERSION "1.3.0-master"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define BUILD 952
 | 
					#define BUILD 975
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define HOSTID "mailarchiver"
 | 
					#define HOSTID "mailarchiver"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										26
									
								
								src/defs.h
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								src/defs.h
									
									
									
									
									
								
							@@ -22,6 +22,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <openssl/sha.h>
 | 
					#include <openssl/sha.h>
 | 
				
			||||||
#include <openssl/ssl.h>
 | 
					#include <openssl/ssl.h>
 | 
				
			||||||
 | 
					#include <netinet/in.h>
 | 
				
			||||||
#include "tai.h"
 | 
					#include "tai.h"
 | 
				
			||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -64,9 +65,6 @@
 | 
				
			|||||||
#define RULE_NO_MATCH -100
 | 
					#define RULE_NO_MATCH -100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef void signal_func (int);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct child {
 | 
					struct child {
 | 
				
			||||||
   pid_t pid;
 | 
					   pid_t pid;
 | 
				
			||||||
   int serial;
 | 
					   int serial;
 | 
				
			||||||
@@ -386,6 +384,26 @@ struct session_ctx {
 | 
				
			|||||||
   struct counters *counters;
 | 
					   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 */
 | 
					#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){
 | 
					void check_and_create_directories(struct __config *cfg, uid_t uid, gid_t gid){
 | 
				
			||||||
   char *p, s[SMALLBUFSIZE];
 | 
					   char *p, s[SMALLBUFSIZE];
 | 
				
			||||||
 | 
					   int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   p = strrchr(cfg->workdir, '/');
 | 
					   p = strrchr(cfg->workdir, '/');
 | 
				
			||||||
   if(p){
 | 
					   if(p){
 | 
				
			||||||
@@ -45,6 +46,11 @@ void check_and_create_directories(struct __config *cfg, uid_t uid, gid_t gid){
 | 
				
			|||||||
      *p = '/';
 | 
					      *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
 | 
					 * 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
 | 
					#ifndef _GNU_SOURCE
 | 
				
			||||||
char *strcasestr(const char *s, const char *find){
 | 
					char *strcasestr(const char *s, const char *find){
 | 
				
			||||||
   char c, sc;
 | 
					   char c, sc;
 | 
				
			||||||
@@ -647,4 +673,3 @@ char *strcasestr(const char *s, const char *find){
 | 
				
			|||||||
   return((char*)s);
 | 
					   return((char*)s);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,7 @@ void get_extractor_list();
 | 
				
			|||||||
void __fatal(char *s);
 | 
					void __fatal(char *s);
 | 
				
			||||||
long tvdiff(struct timeval a, struct timeval b);
 | 
					long tvdiff(struct timeval a, struct timeval b);
 | 
				
			||||||
int searchStringInBuffer(char *s, int len1, char *what, int len2);
 | 
					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);
 | 
					int countCharacterInBuffer(char *p, char c);
 | 
				
			||||||
void replaceCharacterInBuffer(char *p, char from, char to);
 | 
					void replaceCharacterInBuffer(char *p, char from, char to);
 | 
				
			||||||
char *split(char *str, int ch, char *buf, int buflen, int *result);
 | 
					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();
 | 
					int can_i_write_current_directory();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void move_email(struct smtp_session *session);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef _GNU_SOURCE
 | 
					#ifndef _GNU_SOURCE
 | 
				
			||||||
   char *strcasestr(const char *s, const char *find);
 | 
					   char *strcasestr(const char *s, const char *find);
 | 
				
			||||||
#endif
 | 
					#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){
 | 
					static void child_main(struct child *ptr){
 | 
				
			||||||
   char s[INET6_ADDRSTRLEN];
 | 
					   struct import import;
 | 
				
			||||||
   struct sockaddr_storage client_addr;
 | 
					   struct session_data sdata;
 | 
				
			||||||
   socklen_t addr_size;
 | 
					   int tot_msgs = 0;
 | 
				
			||||||
   struct session_ctx sctx;
 | 
					   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;
 | 
					   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){
 | 
					   while(1){
 | 
				
			||||||
      if(received_sighup == 1){
 | 
					      if(received_sighup == 1){
 | 
				
			||||||
@@ -119,35 +127,30 @@ static void child_main(struct child *ptr){
 | 
				
			|||||||
         break;
 | 
					         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);
 | 
					      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){
 | 
					         sleep(2);
 | 
				
			||||||
         if(cfg.verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "child (pid: %d, serial: %d) served enough: %d", getpid(), ptr->messages, ptr->serial);
 | 
					      }
 | 
				
			||||||
         break;
 | 
					      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
 | 
					#ifdef HAVE_MEMCACHED
 | 
				
			||||||
   memcached_shutdown(&(data.memc));
 | 
					   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);
 | 
					   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));
 | 
					      fprintf(stderr, "getaddrinfo for '%s': %s\n", cfg.listen_addr, gai_strerror(rc));
 | 
				
			||||||
      return 1;
 | 
					      return 1;
 | 
				
			||||||
   }
 | 
					   }
 | 
				
			||||||
@@ -466,4 +470,3 @@ int main(int argc, char **argv){
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
   return 0;
 | 
					   return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,7 @@
 | 
				
			|||||||
#include <rules.h>
 | 
					#include <rules.h>
 | 
				
			||||||
#include <sql.h>
 | 
					#include <sql.h>
 | 
				
			||||||
#include <import.h>
 | 
					#include <import.h>
 | 
				
			||||||
 | 
					#include <smtp.h>
 | 
				
			||||||
#include <config.h>
 | 
					#include <config.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -29,6 +30,8 @@
 | 
				
			|||||||
int read_key(struct __config *cfg);
 | 
					int read_key(struct __config *cfg);
 | 
				
			||||||
void insert_offset(struct session_data *sdata, int server_id);
 | 
					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 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);
 | 
					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);
 | 
					int is_blocked_by_tcp_wrappers(int sd);
 | 
				
			||||||
void send_response_to_data(struct session_ctx *sctx, char *rcptto);
 | 
					void send_response_to_data(struct session_ctx *sctx, char *rcptto);
 | 
				
			||||||
void process_written_file(struct session_ctx *sctx);
 | 
					void process_written_file(struct session_ctx *sctx);
 | 
				
			||||||
void process_data(struct session_ctx *sctx);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _PILER_H */
 | 
					#endif /* _PILER_H */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,8 @@
 | 
				
			|||||||
#ifndef _SIG_H
 | 
					#ifndef _SIG_H
 | 
				
			||||||
 #define _SIG_H
 | 
					 #define _SIG_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef void signal_func (int);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void sig_block(int sig);
 | 
					void sig_block(int sig);
 | 
				
			||||||
void sig_unblock(int sig);
 | 
					void sig_unblock(int sig);
 | 
				
			||||||
void sig_catch(int sig, void (*f)());
 | 
					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 <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <strings.h>
 | 
					 | 
				
			||||||
#include <sys/types.h>
 | 
					#include <sys/types.h>
 | 
				
			||||||
#include <sys/socket.h>
 | 
					#include <sys/socket.h>
 | 
				
			||||||
#include <sys/stat.h>
 | 
					#include <sys/stat.h>
 | 
				
			||||||
 | 
					#include <netinet/in.h>
 | 
				
			||||||
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
#include <fcntl.h>
 | 
					#include <fcntl.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
#include <signal.h>
 | 
					 | 
				
			||||||
#include <syslog.h>
 | 
					#include <syslog.h>
 | 
				
			||||||
#include <time.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#include <openssl/ssl.h>
 | 
					#include <openssl/ssl.h>
 | 
				
			||||||
#include <openssl/err.h>
 | 
					#include <openssl/err.h>
 | 
				
			||||||
#include <piler.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){
 | 
					void process_smtp_command(struct smtp_session *session, char *buf){
 | 
				
			||||||
   char tmpbuf[MAXBUFSIZE];
 | 
					   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];
 | 
					   char extensions[SMALLBUFSIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   memset(extensions, 0, sizeof(extensions));
 | 
					   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 tls is not started, but it's enabled in the config
 | 
				
			||||||
   if(sctx->cfg->enable_chunking == 1) strncat(extensions, SMTP_EXTENSION_CHUNKING, sizeof(extensions)-strlen(extensions)-2);
 | 
					   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){
 | 
					   if(SSL_CTX_set_cipher_list(session->ctx, session->cfg->cipher_list) == 0){
 | 
				
			||||||
      sctx->data->ssl = SSL_new(sctx->data->ctx);
 | 
					      syslog(LOG_PRIORITY, "failed to set cipher list: '%s'", session->cfg->cipher_list);
 | 
				
			||||||
      if(sctx->data->ssl){
 | 
					      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){
 | 
					   if(SSL_CTX_use_certificate_file(session->ctx, session->cfg->pemfile, SSL_FILETYPE_PEM) != 1){
 | 
				
			||||||
            strncat(resp, SMTP_RESP_220_READY_TO_START_TLS, resplen);
 | 
					      syslog(LOG_PRIORITY, "cannot load certificate from %s", session->cfg->pemfile);
 | 
				
			||||||
            *starttls = 1;
 | 
					      return 0;
 | 
				
			||||||
            *protocol_state = SMTP_STATE_INIT;
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   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;
 | 
					            return;
 | 
				
			||||||
         } syslog(LOG_PRIORITY, "%s: SSL_set_fd() failed", sctx->sdata->ttmpfile);
 | 
					         } syslog(LOG_PRIORITY, "%s: SSL_set_fd() failed", session->ttmpfile);
 | 
				
			||||||
      } syslog(LOG_PRIORITY, "%s: SSL_new() failed", sctx->sdata->ttmpfile);
 | 
					      } syslog(LOG_PRIORITY, "%s: SSL_new() failed", session->ttmpfile);
 | 
				
			||||||
   } syslog(LOG_PRIORITY, "%s: SSL ctx is null!", sctx->sdata->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){
 | 
					   if(session->protocol_state != SMTP_STATE_HELO && session->protocol_state != SMTP_STATE_PERIOD && session->protocol_state != SMTP_STATE_BDAT){
 | 
				
			||||||
      strncat(resp, SMTP_RESP_503_ERR, resplen);
 | 
					      send(session->socket, SMTP_RESP_503_ERR, strlen(SMTP_RESP_503_ERR), 0);
 | 
				
			||||||
   }
 | 
					   }
 | 
				
			||||||
   else {
 | 
					   else {
 | 
				
			||||||
      if(*protocol_state == SMTP_STATE_PERIOD || *protocol_state == SMTP_STATE_BDAT){
 | 
					      create_id(&(session->ttmpfile[0]), 15);
 | 
				
			||||||
         if(sctx->cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: initiated new transaction", sctx->sdata->ttmpfile);
 | 
					      session->protocol_state = SMTP_STATE_MAIL_FROM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
         unlink(sctx->sdata->ttmpfile);
 | 
					      extractEmail(buf, session->mailfrom);
 | 
				
			||||||
         unlink(sctx->sdata->tmpframe);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
         init_session_data(sctx->sdata, sctx->cfg);
 | 
					      reset_bdat_counters(session);
 | 
				
			||||||
      }
 | 
					      session->tot_len = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      *protocol_state = SMTP_STATE_MAIL_FROM;
 | 
					      send_smtp_response(session, SMTP_RESP_250_OK);
 | 
				
			||||||
 | 
					 | 
				
			||||||
      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);
 | 
					 | 
				
			||||||
   }
 | 
					   }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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){
 | 
					   if(session->protocol_state == SMTP_STATE_MAIL_FROM || session->protocol_state == SMTP_STATE_RCPT_TO){
 | 
				
			||||||
      strncat(resp, SMTP_RESP_503_ERR, resplen);
 | 
					
 | 
				
			||||||
 | 
					      // 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 {
 | 
					   else {
 | 
				
			||||||
      sctx->sdata->fd = open(sctx->sdata->filename, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP);
 | 
					      send_smtp_response(session, SMTP_RESP_503_ERR);
 | 
				
			||||||
      if(sctx->sdata->fd == -1){
 | 
					   }
 | 
				
			||||||
         syslog(LOG_PRIORITY, "%s: %s", ERR_OPEN_TMP_FILE, sctx->sdata->ttmpfile);
 | 
					}
 | 
				
			||||||
         strncat(resp, SMTP_RESP_451_ERR, resplen);
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 {
 | 
					      else {
 | 
				
			||||||
         *protocol_state = SMTP_STATE_DATA;
 | 
					         session->protocol_state = SMTP_STATE_DATA;
 | 
				
			||||||
         strncat(resp, SMTP_RESP_354_DATA_OK, resplen-1);
 | 
					         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){
 | 
					   session->protocol_state = SMTP_STATE_PERIOD;
 | 
				
			||||||
   int n, expected_bdat_len;
 | 
					 | 
				
			||||||
   char puf[MAXBUFSIZE];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
   if(*protocol_state != SMTP_STATE_RCPT_TO){
 | 
					   // TODO: add some error handling
 | 
				
			||||||
      strncat(resp, SMTP_RESP_503_ERR, resplen);
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
   }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
   sctx->bdat_rounds = 0;
 | 
					   fsync(session->fd);
 | 
				
			||||||
   sctx->bdat_last_round = 0;
 | 
					   close(session->fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   while(sctx->bdat_last_round != 1){
 | 
					   session->fd = -1;
 | 
				
			||||||
      sctx->bdat_rounds++;
 | 
					 | 
				
			||||||
      expected_bdat_len = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if(sctx->bdat_rounds == 1){
 | 
					   syslog(LOG_PRIORITY, "received: %s, from=%s, size=%d", session->ttmpfile, session->mailfrom, session->tot_len);
 | 
				
			||||||
         expected_bdat_len = extract_bdat_command(sctx, buf);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
         sctx->sdata->fd = open(sctx->sdata->filename, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP);
 | 
					   move_email(session);
 | 
				
			||||||
         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--;
 | 
					 | 
				
			||||||
         }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      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);
 | 
					   session->buflen = 0;
 | 
				
			||||||
   close(sctx->sdata->fd);
 | 
					   memset(session->buf, 0, SMALLBUFSIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   send_smtp_response(session, buf);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int extract_bdat_command(struct session_ctx *sctx, char *buf){
 | 
					void process_command_quit(struct smtp_session *session, char *buf, int buflen){
 | 
				
			||||||
   int expected_bdat_len=0;
 | 
					   session->protocol_state = SMTP_STATE_FINISHED;
 | 
				
			||||||
   char *p;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
   // determine if this is the last BDAT command
 | 
					   snprintf(buf, buflen-1, SMTP_RESP_221_GOODBYE, session->cfg->hostid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   p = strcasestr(buf, " LAST");
 | 
					   send_smtp_response(session, buf);
 | 
				
			||||||
   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;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int read_bdat_data(struct session_ctx *sctx, int expected_bdat_len){
 | 
					void process_command_reset(struct smtp_session *session){
 | 
				
			||||||
   int n, read_bdat_len=0, written_bdat_len=0;
 | 
					   send_smtp_response(session, SMTP_RESP_250_OK);
 | 
				
			||||||
   char puf[MAXBUFSIZE];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
   while(read_bdat_len < expected_bdat_len){
 | 
					   session->tot_len = 0;
 | 
				
			||||||
      if((n = recvtimeoutssl(sctx->new_sd, &puf[0], sizeof(puf), TIMEOUT, sctx->sdata->tls, sctx->data->ssl)) > 0){
 | 
					   session->fd = -1;
 | 
				
			||||||
         read_bdat_len += n;
 | 
					   session->protocol_state = SMTP_STATE_HELO;
 | 
				
			||||||
         written_bdat_len += write(sctx->sdata->fd, puf, n);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
   }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
   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
 | 
					#ifndef _SMTP_H
 | 
				
			||||||
 #define _SMTP_H
 | 
					 #define _SMTP_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void process_command_ehlo_lhlo(struct session_ctx *sctx, int *protocol_state, char *resp, int resplen);
 | 
					#include <piler.h>
 | 
				
			||||||
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);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
int read_bdat_data(struct session_ctx *sctx, int expected_bdat_len);
 | 
					void process_smtp_command(struct smtp_session *session, char *buf);
 | 
				
			||||||
int extract_bdat_command(struct session_ctx *sctx, 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 "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_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_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_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_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"
 | 
					#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_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_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 "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_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_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"
 | 
					#define SMTP_RESP_550_ERR_YOU_ARE_BANNED_BY_LOCAL_POLICY "550 You are banned by local policy\r\n"
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user