mirror of
				https://bitbucket.org/jsuto/piler.git
				synced 2025-11-04 14:12:27 +01:00 
			
		
		
		
	code refactoring
Change-Id: I6b634f1cc57b69a243259ad424b7c7aab6b93736 Signed-off-by: SJ <sj@acts.hu>
This commit is contained in:
		
							
								
								
									
										2
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								configure
									
									
									
									
										vendored
									
									
								
							@@ -4866,7 +4866,7 @@ echo; echo
 | 
			
		||||
 | 
			
		||||
CFLAGS="$static -O2 -Wall -g"
 | 
			
		||||
LIBS="$antispam_libs $sunos_libs "
 | 
			
		||||
OBJS="dirs.o base64.o misc.o counters.o cfg.o sig.o decoder.o hash.o parser.o parser_utils.o rules.o smtp.o 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"
 | 
			
		||||
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 bdat.o message.o attachment.o digest.o store.o archive.o tai.o import.o import_maildir.o import_mailbox.o import_pop3.o import_imap.o import_gui.o imap.o pop3.o extract.o mydomains.o $objs"
 | 
			
		||||
 | 
			
		||||
ac_config_files="$ac_config_files Makefile src/Makefile etc/Makefile util/Makefile init.d/Makefile unit_tests/Makefile contrib/imap/Makefile"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -544,7 +544,7 @@ echo; echo
 | 
			
		||||
 | 
			
		||||
CFLAGS="$static -O2 -Wall -g"
 | 
			
		||||
LIBS="$antispam_libs $sunos_libs "
 | 
			
		||||
OBJS="dirs.o base64.o misc.o counters.o cfg.o sig.o decoder.o hash.o parser.o parser_utils.o rules.o smtp.o 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"
 | 
			
		||||
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 bdat.o message.o attachment.o digest.o store.o archive.o tai.o import.o import_maildir.o import_mailbox.o import_pop3.o import_imap.o import_gui.o imap.o pop3.o extract.o mydomains.o $objs"
 | 
			
		||||
 | 
			
		||||
AC_CONFIG_FILES([Makefile src/Makefile etc/Makefile util/Makefile init.d/Makefile unit_tests/Makefile contrib/imap/Makefile])
 | 
			
		||||
AC_OUTPUT
 | 
			
		||||
 
 | 
			
		||||
@@ -48,7 +48,7 @@ libpiler.a: $(OBJS) $(SQL_OBJS)
 | 
			
		||||
	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)
 | 
			
		||||
	$(CC) $(CFLAGS) $(INCDIR) $(DEFS) -o $@ $< cfg.o misc.o tai.o smtp.o session.o dirs.o sig.o bdat.o $(LIBS) $(LIBDIR)
 | 
			
		||||
 | 
			
		||||
pilerget: pilerget.c libpiler.a
 | 
			
		||||
	$(CC) $(CFLAGS) $(INCDIR) $(DEFS) -o $@ $< -lpiler $(LIBS) $(LIBDIR)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										237
									
								
								src/piler-smtp.c
									
									
									
									
									
								
							
							
						
						
									
										237
									
								
								src/piler-smtp.c
									
									
									
									
									
								
							@@ -41,110 +41,6 @@ struct passwd *pwd;
 | 
			
		||||
struct smtp_session *session, **sessions=NULL;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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 slot, int sd){
 | 
			
		||||
   session->slot = slot;
 | 
			
		||||
 | 
			
		||||
   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){
 | 
			
		||||
 | 
			
		||||
      if(session->use_ssl == 1){
 | 
			
		||||
         SSL_shutdown(session->ssl);
 | 
			
		||||
         SSL_free(session->ssl);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if(session->ctx) SSL_CTX_free(session->ctx);
 | 
			
		||||
 | 
			
		||||
      free(session);
 | 
			
		||||
   }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void p_clean_exit(){
 | 
			
		||||
   int i;
 | 
			
		||||
 | 
			
		||||
@@ -173,40 +69,6 @@ void fatal(char *s){
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int get_session_slot(){
 | 
			
		||||
   int i;
 | 
			
		||||
 | 
			
		||||
   for(i=0; i<cfg.max_connections; i++){
 | 
			
		||||
      if(sessions[i] == NULL) return i;
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct smtp_session *get_session_by_socket(int socket){
 | 
			
		||||
   int i;
 | 
			
		||||
 | 
			
		||||
   for(i=0; i<cfg.max_connections; i++){
 | 
			
		||||
      if(sessions[i] && sessions[i]->socket == socket) return sessions[i];
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void tear_down_client(int slot){
 | 
			
		||||
   syslog(LOG_PRIORITY, "disconnected from %s", sessions[slot]->remote_host);
 | 
			
		||||
 | 
			
		||||
   close(sessions[slot]->socket);
 | 
			
		||||
 | 
			
		||||
   free_smtp_session(sessions[slot]);
 | 
			
		||||
   sessions[slot] = NULL;
 | 
			
		||||
 | 
			
		||||
   num_connections--;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void check_for_client_timeout(){
 | 
			
		||||
   time_t now;
 | 
			
		||||
   int i;
 | 
			
		||||
@@ -217,7 +79,7 @@ void check_for_client_timeout(){
 | 
			
		||||
      for(i=0; i<cfg.max_connections; i++){
 | 
			
		||||
         if(sessions[i] && now - sessions[i]->lasttime >= cfg.smtp_timeout){
 | 
			
		||||
            syslog(LOG_PRIORITY, "client %s timeout", sessions[i]->remote_host);
 | 
			
		||||
            tear_down_client(sessions[i]->slot);
 | 
			
		||||
            tear_down_session(sessions, sessions[i]->slot, &num_connections);
 | 
			
		||||
         }
 | 
			
		||||
      }
 | 
			
		||||
   }
 | 
			
		||||
@@ -226,72 +88,6 @@ void check_for_client_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 start_new_session(int socket){
 | 
			
		||||
   char smtp_banner[SMALLBUFSIZE];
 | 
			
		||||
   int slot;
 | 
			
		||||
 | 
			
		||||
   // Uh-oh! We have enough connections to serve already
 | 
			
		||||
   if(num_connections >= cfg.max_connections){
 | 
			
		||||
      syslog(LOG_PRIORITY, "too many connections (%d), cannot accept socket %d", num_connections, socket);
 | 
			
		||||
      send(socket, SMTP_RESP_421_ERR_ALL_PORTS_ARE_BUSY, strlen(SMTP_RESP_421_ERR_ALL_PORTS_ARE_BUSY), 0);
 | 
			
		||||
      close(socket);
 | 
			
		||||
      return -1;
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_LIBWRAP
 | 
			
		||||
   if(is_blocked_by_tcp_wrappers(socket) == 1){
 | 
			
		||||
      close(socket);
 | 
			
		||||
      return -1;
 | 
			
		||||
   }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
   slot = get_session_slot();
 | 
			
		||||
 | 
			
		||||
   if(slot >= 0 && sessions[slot] == NULL){
 | 
			
		||||
      sessions[slot] = malloc(sizeof(struct smtp_session));
 | 
			
		||||
      if(sessions[slot]){
 | 
			
		||||
         init_smtp_session(sessions[slot], slot, socket);
 | 
			
		||||
         snprintf(smtp_banner, sizeof(smtp_banner)-1, SMTP_RESP_220_BANNER, cfg.hostid);
 | 
			
		||||
         send(socket, smtp_banner, strlen(smtp_banner), 0);
 | 
			
		||||
 | 
			
		||||
         num_connections++;
 | 
			
		||||
 | 
			
		||||
         return 0;
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
         syslog(LOG_PRIORITY, "ERROR: malloc() in start_new_session()");
 | 
			
		||||
      }
 | 
			
		||||
   }
 | 
			
		||||
   else {
 | 
			
		||||
      syslog(LOG_PRIORITY, "ERROR: couldn't find a slot for the connection");
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   send(socket, SMTP_RESP_421_ERR_TMP, strlen(SMTP_RESP_421_ERR_TMP), 0);
 | 
			
		||||
   close(socket);
 | 
			
		||||
 | 
			
		||||
   return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void initialise_configuration(){
 | 
			
		||||
   cfg = read_config(configfile);
 | 
			
		||||
 | 
			
		||||
@@ -320,6 +116,7 @@ int main(int argc, char **argv){
 | 
			
		||||
   int listenerfd, client_sockfd;
 | 
			
		||||
   int i, n, daemonise=0;
 | 
			
		||||
   int client_len = sizeof(struct sockaddr_storage);
 | 
			
		||||
   ssize_t readlen;
 | 
			
		||||
   struct sockaddr_storage client_address;
 | 
			
		||||
   char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
 | 
			
		||||
   char readbuf[BIGBUFSIZE];
 | 
			
		||||
@@ -409,7 +206,6 @@ int main(int argc, char **argv){
 | 
			
		||||
         if((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))){
 | 
			
		||||
            syslog(LOG_PRIORITY, "ERROR: epoll error");
 | 
			
		||||
            close(events[i].data.fd);
 | 
			
		||||
            // we have to tear_down_client as well if not the listening socket?
 | 
			
		||||
            continue;
 | 
			
		||||
         }
 | 
			
		||||
 | 
			
		||||
@@ -447,7 +243,7 @@ int main(int argc, char **argv){
 | 
			
		||||
                  break;
 | 
			
		||||
               }
 | 
			
		||||
 | 
			
		||||
               start_new_session(client_sockfd);
 | 
			
		||||
               start_new_session(sessions, client_sockfd, &num_connections, &cfg);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            continue;
 | 
			
		||||
@@ -458,12 +254,8 @@ int main(int argc, char **argv){
 | 
			
		||||
 | 
			
		||||
         else {
 | 
			
		||||
            int done = 0;
 | 
			
		||||
            ssize_t count;
 | 
			
		||||
 | 
			
		||||
            // should the following work here as well?
 | 
			
		||||
            // ioctl(events[i].data.fd, FIONREAD, &bytes_to_read);
 | 
			
		||||
 | 
			
		||||
            session = get_session_by_socket(events[i].data.fd);
 | 
			
		||||
            session = get_session_by_socket(sessions, cfg.max_connections, events[i].data.fd);
 | 
			
		||||
            if(session == NULL){
 | 
			
		||||
               syslog(LOG_PRIORITY, "ERROR: cannot find session for this socket: %d", events[i].data.fd);
 | 
			
		||||
               close(events[i].data.fd);
 | 
			
		||||
@@ -476,13 +268,13 @@ int main(int argc, char **argv){
 | 
			
		||||
               memset(readbuf, 0, sizeof(readbuf));
 | 
			
		||||
 | 
			
		||||
               if(session->use_ssl == 1)
 | 
			
		||||
                  count = SSL_read(session->ssl, (char*)&readbuf[0], sizeof(readbuf)-1);
 | 
			
		||||
                  readlen = SSL_read(session->ssl, (char*)&readbuf[0], sizeof(readbuf)-1);
 | 
			
		||||
               else
 | 
			
		||||
                  count = read(events[i].data.fd, (char*)&readbuf[0], sizeof(readbuf)-1);
 | 
			
		||||
                  readlen = read(events[i].data.fd, (char*)&readbuf[0], sizeof(readbuf)-1);
 | 
			
		||||
 | 
			
		||||
               if(cfg.verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "got %ld bytes to read", count);
 | 
			
		||||
               if(cfg.verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "got %ld bytes to read", readlen);
 | 
			
		||||
 | 
			
		||||
               if(count == -1){
 | 
			
		||||
               if(readlen == -1){
 | 
			
		||||
                  /* If errno == EAGAIN, that means we have read all data. So go back to the main loop. */
 | 
			
		||||
                  if(errno != EAGAIN){
 | 
			
		||||
                     syslog(LOG_PRIORITY, "read");
 | 
			
		||||
@@ -490,27 +282,22 @@ int main(int argc, char **argv){
 | 
			
		||||
                  }
 | 
			
		||||
                  break;
 | 
			
		||||
               }
 | 
			
		||||
               else if(count == 0){
 | 
			
		||||
               else if(readlen == 0){
 | 
			
		||||
                  /* End of file. The remote has closed the connection. */
 | 
			
		||||
                  done = 1;
 | 
			
		||||
                  break;
 | 
			
		||||
               }
 | 
			
		||||
 | 
			
		||||
               handle_data(session, &readbuf[0], count);
 | 
			
		||||
               handle_data(session, &readbuf[0], readlen);
 | 
			
		||||
 | 
			
		||||
               if(session->protocol_state == SMTP_STATE_BDAT && session->bad == 1){
 | 
			
		||||
                  tear_down_client(session->slot);
 | 
			
		||||
                  done = 0; // to prevent the repeated tear down of connection
 | 
			
		||||
                  done = 1;
 | 
			
		||||
                  break;
 | 
			
		||||
               }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if(done){
 | 
			
		||||
               printf("Closed connection on descriptor %d\n", events[i].data.fd);
 | 
			
		||||
 | 
			
		||||
               /* Closing the descriptor will make epoll remove it from the set of descriptors which are monitored. */
 | 
			
		||||
               //close(events[i].data.fd);
 | 
			
		||||
               tear_down_client(session->slot);
 | 
			
		||||
               tear_down_session(sessions, session->slot, &num_connections);
 | 
			
		||||
            }
 | 
			
		||||
         }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -67,6 +67,12 @@ int retrieve_file_from_archive(char *filename, int mode, char **buffer, FILE *de
 | 
			
		||||
void load_mydomains(struct session_data *sdata, struct __data *data, struct __config *cfg);
 | 
			
		||||
int is_email_address_on_my_domains(char *email, struct __data *data);
 | 
			
		||||
 | 
			
		||||
int start_new_session(struct smtp_session **sessions, int socket, int *num_connections, struct __config *cfg);
 | 
			
		||||
void tear_down_session(struct smtp_session **sessions, int slot, int *num_connections);
 | 
			
		||||
struct smtp_session *get_session_by_socket(struct smtp_session **sessions, int max_connections, int socket);
 | 
			
		||||
void handle_data(struct smtp_session *session, char *readbuf, int readlen);
 | 
			
		||||
void free_smtp_session(struct smtp_session *session);
 | 
			
		||||
 | 
			
		||||
void child_sighup_handler(int sig);
 | 
			
		||||
void child_main(struct child *ptr);
 | 
			
		||||
pid_t child_make(struct child *ptr);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										215
									
								
								src/session.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								src/session.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,215 @@
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <piler.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int get_session_slot(struct smtp_session **sessions, int max_connections);
 | 
			
		||||
void init_smtp_session(struct smtp_session *session, int slot, int sd, struct __config *cfg);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_LIBWRAP
 | 
			
		||||
int is_blocked_by_tcp_wrappers(int sd){
 | 
			
		||||
   struct request_info req;
 | 
			
		||||
 | 
			
		||||
   request_init(&req, RQ_DAEMON, "piler", 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 start_new_session(struct smtp_session **sessions, int socket, int *num_connections, struct __config *cfg){
 | 
			
		||||
   char smtp_banner[SMALLBUFSIZE];
 | 
			
		||||
   int slot;
 | 
			
		||||
 | 
			
		||||
   /*
 | 
			
		||||
    * We have enough connections to serve already
 | 
			
		||||
    */
 | 
			
		||||
 | 
			
		||||
   if(*num_connections >= cfg->max_connections){
 | 
			
		||||
      syslog(LOG_PRIORITY, "too many connections (%d), cannot accept socket %d", *num_connections, socket);
 | 
			
		||||
      send(socket, SMTP_RESP_421_ERR_ALL_PORTS_ARE_BUSY, strlen(SMTP_RESP_421_ERR_ALL_PORTS_ARE_BUSY), 0);
 | 
			
		||||
      close(socket);
 | 
			
		||||
      return -1;
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_LIBWRAP
 | 
			
		||||
   if(is_blocked_by_tcp_wrappers(socket) == 1){
 | 
			
		||||
      close(socket);
 | 
			
		||||
      return -1;
 | 
			
		||||
   }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
   slot = get_session_slot(sessions, cfg->max_connections);
 | 
			
		||||
 | 
			
		||||
   if(slot >= 0 && sessions[slot] == NULL){
 | 
			
		||||
      sessions[slot] = malloc(sizeof(struct smtp_session));
 | 
			
		||||
      if(sessions[slot]){
 | 
			
		||||
         init_smtp_session(sessions[slot], slot, socket, cfg);
 | 
			
		||||
         snprintf(smtp_banner, sizeof(smtp_banner)-1, SMTP_RESP_220_BANNER, cfg->hostid);
 | 
			
		||||
         send(socket, smtp_banner, strlen(smtp_banner), 0);
 | 
			
		||||
 | 
			
		||||
         (*num_connections)++;
 | 
			
		||||
 | 
			
		||||
         return 0;
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
         syslog(LOG_PRIORITY, "ERROR: malloc() in start_new_session()");
 | 
			
		||||
      }
 | 
			
		||||
   }
 | 
			
		||||
   else {
 | 
			
		||||
      syslog(LOG_PRIORITY, "ERROR: couldn't find a slot for the connection");
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   send(socket, SMTP_RESP_421_ERR_TMP, strlen(SMTP_RESP_421_ERR_TMP), 0);
 | 
			
		||||
   close(socket);
 | 
			
		||||
 | 
			
		||||
   return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int get_session_slot(struct smtp_session **sessions, int max_connections){
 | 
			
		||||
   int i;
 | 
			
		||||
 | 
			
		||||
   for(i=0; i<max_connections; i++){
 | 
			
		||||
      if(sessions[i] == NULL) return i;
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct smtp_session *get_session_by_socket(struct smtp_session **sessions, int max_connections, int socket){
 | 
			
		||||
   int i;
 | 
			
		||||
 | 
			
		||||
   for(i=0; i<max_connections; i++){
 | 
			
		||||
      if(sessions[i] && sessions[i]->socket == socket) return sessions[i];
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void init_smtp_session(struct smtp_session *session, int slot, int sd, struct __config *cfg){
 | 
			
		||||
   session->slot = slot;
 | 
			
		||||
 | 
			
		||||
   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){
 | 
			
		||||
 | 
			
		||||
      if(session->use_ssl == 1){
 | 
			
		||||
         SSL_shutdown(session->ssl);
 | 
			
		||||
         SSL_free(session->ssl);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if(session->ctx) SSL_CTX_free(session->ctx);
 | 
			
		||||
 | 
			
		||||
      free(session);
 | 
			
		||||
   }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void tear_down_session(struct smtp_session **sessions, int slot, int *num_connections){
 | 
			
		||||
   syslog(LOG_PRIORITY, "disconnected from %s", sessions[slot]->remote_host);
 | 
			
		||||
 | 
			
		||||
   close(sessions[slot]->socket);
 | 
			
		||||
 | 
			
		||||
   free_smtp_session(sessions[slot]);
 | 
			
		||||
   sessions[slot] = NULL;
 | 
			
		||||
 | 
			
		||||
   (*num_connections)--;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user