Blockin websites mail sending (PHP but not only)

Discussion in 'Tips/Tricks/Mods' started by hyppoCom, Oct 2, 2023.

  1. hyppoCom

    hyppoCom New Member

    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);
    }
    
     
    Last edited: Oct 3, 2023
    ahrasis likes this.

Share This Page