A very common problem is to prevent your sites to use your server to SPAM: here's how I solved this. My ISPConfig installation does not provide Mail Server service My solution assumes that nobody should send email using a regular SMTP connection, but only using an SMTPs authenticated relay DRAFT: - Block the tcp/25 in and out - Install an SMTPs MTA (ESMTP) that uses the webserver user configuration to send email - Replace /usr/sbin/sendmail with a custom program that calls ESMTP DESCRIPTION: Firewall First I blocked port 25 in and out with: Code: iptables -I ufw-before-input -p tcp -m tcp -dport 25 -j REJECT iptables -I ufw-before-logging-output -p tcp -m tcp -dport 25 -j REJECT ESMTP Got source files of ESMTP (of Jose Fonseca) project at esmtp.sourceforge.net (download at sourceforge.net/projects/esmtp/files/) and installed and changed a bit to decrypt the password read from the configuration file (the key is hard-coded, but it's just to not leave the plain password). The configuration file is read from the home directory of the user (tipically /var/www/clients/clientX/webY), and it's called .esmtprc A tipical example of .esmtprc file is: Code: helo=my-ispconfig-server.mydomain.tld hostname=smtp.gmail.com:587 starttls=required [email protected] password=ae498734983724987fde9837249872358 The modified version of esmtp requires the change of the file parser.y (remember to change the encryption iv) Code: *** parser.y-orig --- parser.y *************** *** 21,26 **** --- 21,30 ---- #endif #include <libesmtp.h> + #include <openssl/aes.h> + #include <stdarg.h> + #include <syslog.h> + #include <time.h> #include "main.h" #include "smtp.h" *************** *** 105,111 **** /* future global options should also have the form SET <name> optmap <value> */ statement : HOSTNAME map STRING { identity->host = xstrdup($3); SET_DEFAULT_IDENTITY; } | USERNAME map STRING { identity->user = xstrdup($3); SET_DEFAULT_IDENTITY; } ! | PASSWORD map STRING { identity->pass = xstrdup($3); SET_DEFAULT_IDENTITY; } | STARTTLS map DISABLED { identity->starttls = Starttls_DISABLED; SET_DEFAULT_IDENTITY; } | STARTTLS map ENABLED { identity->starttls = Starttls_ENABLED; SET_DEFAULT_IDENTITY; } | STARTTLS map REQUIRED { identity->starttls = Starttls_REQUIRED; SET_DEFAULT_IDENTITY; } --- 109,115 ---- /* future global options should also have the form SET <name> optmap <value> */ statement : HOSTNAME map STRING { identity->host = xstrdup($3); SET_DEFAULT_IDENTITY; } | USERNAME map STRING { identity->user = xstrdup($3); SET_DEFAULT_IDENTITY; } ! | PASSWORD map STRING { identity->pass = pass_decrypt($3); SET_DEFAULT_IDENTITY; } | STARTTLS map DISABLED { identity->starttls = Starttls_DISABLED; SET_DEFAULT_IDENTITY; } | STARTTLS map ENABLED { identity->starttls = Starttls_ENABLED; SET_DEFAULT_IDENTITY; } | STARTTLS map REQUIRED { identity->starttls = Starttls_REQUIRED; SET_DEFAULT_IDENTITY; } *************** *** 300,304 **** --- 304,333 ---- exit(EX_CONFIG); } + /* AES-128 bit CBC Decryption */ + char *pass_decrypt(char *pass) + { + unsigned char dec_out[80]; + unsigned char aes_key[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + unsigned char data[80]; + int r,x,size; + unsigned char iv[16]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10}; // ENCRYPTION KEY: CHANGE THIS + for(r=0,size=0; r<strlen(pass); r+=2,size++) { + if(sscanf(&pass[r],"%02x",&data[r/2])!=1) break; + } + if(size<16) return(strdup(pass)); + AES_KEY dec_key; + memset(dec_out,0,sizeof(dec_out)); + AES_set_decrypt_key(aes_key,sizeof(aes_key)*8,&dec_key); // Size of key is in bits + AES_cbc_encrypt(data,dec_out,size,&dec_key,iv,AES_DECRYPT); + for(r=0; dec_out[r]>0; r++) { + if(dec_out[r]<32 || dec_out[r]>'~') { + dec_out[r]=0; + break; + } + } + return(strdup(dec_out)); + } + /* easier to do this than cope with variations in where the library lives */ int yywrap(void) { return 1; } Sendmail modified This is the modified version of sendmail that calls esmtp Replace in /usr/sbin/sendmail and chmod +s Code: // sendmail.c // vim: tabstop=4:shiftwidth=4 // Replacement per /usr/sbin/sendmail che chiama esmtp // Prima controlla esistenza e corretta configurazione di .estprc #include <stdio.h> #include <stdlib.h> #include <pwd.h> #include <unistd.h> #include <syslog.h> #include <string.h> #include <time.h> #include <sys/stat.h> void checkESMTPRC(struct passwd *pwd) { time_t tt; struct tm *tm; FILE *FP; char buf[80],*p,*user; char passok=0; FP=fopen(".esmtprc","r"); if(!FP) { syslog(LOG_INFO,"missing %s .esmtprc",pwd->pw_name); exit(1); } while(fgets(buf,sizeof(buf)-1,FP)) { p=strchr(buf,'#'); if(p) *p='\0'; p=strchr(buf,'='); if(!p) continue; if(p) *p='\0'; // printf("%s/%s",buf,p+1); if(!strcmp(buf,"password")) passok++; else if(!strcmp(buf,"username")) { passok++; user=strdup(p+1); } else if(!strcmp(buf,"hostname")) passok++; if(passok==3) break; } time(&tt); tm=localtime(&tt); if(passok!=3) { syslog(LOG_INFO,"hostname/username/password missing in %s .esmtprc",pwd->pw_name); exit(1); } p=strchr(user,'\n'); *p='\0'; fprintf(stderr,"%02d/%02d/%02d %02d:%02d:%02d sendmail-esmtp %s\n",tm->tm_mday,tm->tm_mon+1,tm->tm_year+1900,tm->tm_hour,tm->tm_min,tm->tm_sec,user); fflush(stderr); } int main(int ac, char *av[]) { FILE *FP; uid_t orig_uid, orig_gid; struct passwd *pwd; char *esmtp_binary="/usr/bin/esmtp"; if(strcmp(av[0],"mailq")==0) { return(0); } openlog("sendmail-esmtp",0,LOG_MAIL); orig_uid=getuid(); orig_gid=getgid(); seteuid(0); pwd=getpwuid(orig_uid); seteuid(orig_uid); setegid(orig_gid); umask(0077); setenv("HOME",pwd->pw_dir,1); setenv("USER",pwd->pw_name,1); syslog(LOG_INFO,"user=%s (#%d:%d) home=%s",pwd->pw_name,getuid(),getgid(),pwd->pw_dir); if(chdir(pwd->pw_dir)!=0) { syslog(LOG_INFO,"Can't chdir(%s)",pwd->pw_dir); fprintf(stderr,"Can't chdir('%s')\n",pwd->pw_dir); exit(1); } FP=freopen("logs/mail.log","a",stderr); if(!FP) FP=freopen("mail.log","a",stderr); if(!FP) FP=freopen("private/mail.log","a",stderr); checkESMTPRC(pwd); execv(esmtp_binary,av); syslog(LOG_CRIT,"Failed execution of %s",esmtp_binary); fprintf(stderr,"Failed execution of %s\n",esmtp_binary); fflush(stderr); closelog(); return(1); }