UBUNTU SMTP: POSTFIX, DOVECOT, MYSQL

Standard

step-by-step SMTP server configuration

server OS: ubuntu 16.04
SMTP service: Postfix
IMAP service: Dovecot
external database: MySQL 5.7

server hostname: smtp.test.com

SSH login into the machine as root and install Postfix, Dovecot and MySQL integrations
# apt-get update
# apt­get install postfix postfix­mysql dovecot­core dovecot­imapd dovecot­lmtpd dovecot­mysql

the data inserted during the Postifix configuration wizard:
– Internet Site
– test.com
they can be modified in the file /etc/main.cfg

MYSQL SERVER CONFIGURATION
# apt-get install mysql-server-5.7

create a MySQL root user before starting using MySQL Server and login
# mysql -u root -p[here-the-password-without-blank]

create a new database, called ims (in-mail-server) to manage domains and e-mail users
mysql> CREATE DATABASE ims;

create a specific in-mail-user only for this database (don’t use root user for queries)
mysql> GRANT SELECT ON ims.* TO ‘imu’@’127.0.0.1’ IDENTIFIED BY ‘imp123’;

mysql> FLUSH PRIVILEGES;

select the inmailserver database and create two tables: for domains and for users
mysql> USE ims;

mysql> CREATE TABLE `virtual_domains` (`id` INT NOT NULL AUTO_INCREMENT,`name` VARCHAR(50) NOT NULL,PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;

mysql> CREATE TABLE `virtual_users` (`id` INT NOT NULL AUTO_INCREMENT,`domain_id` INT NOT NULL,`password` VARCHAR(106) NOT NULL,`email` VARCHAR(120) NOT NULL,PRIMARY KEY (`id`),UNIQUE KEY `email` (`email`),FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert the domains in the virtual_domains table
mysql> INSERT INTO `ims`.`virtual_domains`(`id` ,`name`)VALUES(‘1’, ‘test.com’),(‘2’, ‘test2.com’),(‘3’, ‘test3.com’);

mysql> INSERT INTO `ims`.`virtual_users`(`id`, `domain_id`, `password` , `email`) VALUES (‘1’, ‘1’, ENCRYPT(‘NyreI0Y2WfTCUQqRvigPxWtmS’, CONCAT(‘$6$’, SUBSTRING(SHA(RAND()), -16))), ‘send@test.com’), (‘2’, ‘2’, ENCRYPT(‘hrZT#8[RF2{ruiGwu’, CONCAT(‘$6$’, SUBSTRING(SHA(RAND()), -16))), ‘send@test2.com’), (‘3’, ‘3’, ENCRYPT(‘tukrXZ19lDIWYITtACfgPZhnb’, CONCAT(‘$6$’, SUBSTRING(SHA(RAND()), -16))), ‘send@test3.com’);

POSTFIX CONFIGURATION
generate a free Dovecot SSL certificate (self signed )
# openssl req ­new ­x509 ­days 1000 ­nodes ­out “/etc/ssl/certs/dovecot.pem” ­keyout “/etc/ssl/private/dovecot.key”

open the main.cf file and modify it like this
# nano /etc/postfix/main.cf

modify this section from:
#smtpd_tls_cert_file=/etc/ssl/certs/ssl­cert­snakeoil.pem
#smtpd_tls_key_file=/etc/ssl/private/ssl­cert­snakeoil.key
#smtpd_use_tls=yes
#smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
#smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

to:
smtpd_tls_cert_file=/etc/ssl/certs/dovecot.pem
smtpd_tls_key_file=/etc/ssl/private/dovecot.key
smtpd_use_tls = yessmtpd_tls_auth_only = yes

change these parameters:
mydestination = localhost
myhostname = smtp.test.com

add these lines:
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_recipient_restrictions = permit_sasl_authenticated permit_mynetworks reject_unauth_destination

modify the method to save email to local mailboxes from LDA to LMTP:
virtual_transport = lmtp:unix:private/dovecot­lmtp

enable local mail delivery for all the domains listed in the MySQL database (tell Postfix that is used an external database to manage the domains and users):
virtual_mailbox_domains = mysql:/etc/postfix/mysql­virtual­mailbox­domains.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql­virtual­mailbox­maps.cf
virtual_alias_maps = mysql:/etc/postfix/mysql­virtual­alias­maps.cf

create these 3 configuration files that will contain the informations to query the database
# cd /etc/postfix/

# vi mysql-virtual-mailbox-domains.cf
user = imu
password = imp123
hosts = 127.0.0.1
dbname = ims
serverquery = SELECT 1 FROM virtual_domains WHERE name='%s'

# vi mysql­virtual­mailbox­maps.cf
user = imu
password = imp123
hosts = 127.0.0.1
dbname = ims
serverquery = SELECT 1 FROM virtual_users WHERE email='%s'

to test if they work:
# service postfix restart

# postmap ­q test.com mysql:/etc/postfix/mysql­virtual­mailbox­domains.cf
have to output 1

# postmap ­q test2.com mysql:/etc/postfix/mysql­virtual­mailbox­domains.cf
have to output 1

# postmap ­q test3.com mysql:/etc/postfix/mysql­virtual­mailbox­domains.cf
have to output 1

modify master.conf
# nano /etc/posfix/master.conf
decomment these lines:
submission inet n - y - - smptpd
- o syslog_name=postfix/submission
- o smtpd_tls_security_level=encrypt
- o smtpd_sasl_auth_enable=yes
- o smtpd_client_restrictions=permit_sasl_authenticated,reject

# service postfix restart

DOVECOT CONFIGURATION
these configuration files will allow IMAP protocol to connect to the external database and to Postfix
/etc/dovecot/dovecot.conf
/etc/dovecot/dovecot-sql-conf.ext
/etc/dovecot/conf.d/10-mail.conf
/etc/dovecot/conf.d/10-auth.conf
/etc/dovecot/conf.d/auth-sql.conf.ext
/etc/dovecot/conf.d/10-master.conf
/etc/dovecot/conf.d/10-ssl.conf

/etc/dovecot/dovecot.conf
uncomment it:
!include conf.d/*.conf

enable imap and lmtp:
!include_try /usr/share/dovecot/protocols.d/*.protocol
protocols = imap lmtp

/etc/dovecot/conf.d/10-mail.conf
update the “mail_location” parameter in:
mail_location = maildir:/var/mail/vhosts/%d/%n

set “mail_privileged_group” parameter to “mail”:
mail_privileged_group = mail

***
for that to work, create set mail folders for each domains in the MySQL table inside this folder “/var/mail/vhosts” and set proper ownerships/permissions
# mkdir ­p /var/mail/vhosts/test.com
# mkdir ­p /var/mail/vhosts/test2.com
# mkdir ­p /var/mail/vhosts/test3.com

# groupadd -g 5000 vmail
# useradd -g vmail -u 5000 vmail -d /var/mail
# chown -R vmail:vmail /var/mail

***
/etc/dovecot/conf.d/10-auth.conf
to ensure security:
disable_plaintext_auth = yes
auth_mechanisms = plain login

comment:
#!include auth-system.conf.ext
decomment:
!include auth-sql.conf.ext

/etc/dovecot/dovecot-sql.conf.ext
uncomment and set to:
driver = mysql

set the connection parameters:
connect = host =127.0.0.1
dbname=ims
user=imu
password=imp123

modify password default scheme and the query for it:
default_pass_scheme = SHA512-CRYPT
password_query = SELECT email as user, password FROM virtual_users WHERE email='%u';

***
set permissions on the /etc/dovecot directory so the vmail user can use it
# chown -R vmail:dovecot /etc/dovecot
# chmod -R o-rwx /etc/dovecot

***
/etc/dovecot/conf.d/10-master.conf
change all these sections, so that they are the same as the screenshoots
dovecot-imapdovecot-lmtpdovecto_suthorkerservi_auth

/etc/dovecot/conf.d/10-ssl.conf
change this parameter to enable SSL for the incoming/outgoing connections:
ssl = required

specify the SSL cert and key file location:
ssl_cert = </etc/ssl/certs/dovecot.pem
ssl_key = </etc/ssl/private/dovecot.key

# service dovecot restart

Advertisements

JS SWITCH

Standard

when there are a lot of choices that a program has to cover, instead of writing an else if statement each time, it’s possible to use the switch syntax

switch(expression){

case ‘ ‘:
// do things for this first case;
break;

case ‘ ‘:
// do things for this second case;
break;

default:
// do a default action if there is no matches;

switch allows you to preset a number of options (called cases), then check an expression to see if it matches any of them
if there is a match, the program will perform the action for the matching case
if there’s no match, a default option can be set and executed

var lunch = prompt(“what do you want for lunch?”,”sandwich, salad or pizza?”);

switch(lunch){

case ‘sandwich’:
console.log(“one sandwich, coming up”);
break;

case ‘salad’:
console.log(“sounds good, how about a caesar salad?”);
break;

case ‘pizza’:
console.log(“yummy, pizza”);
break;

case ‘pie’:
console.log(“pie’s not a meal”);
break;

default:
console.log(“huh, I’m not sure what ” + lunch + ” is”);
}

JS ISNAN

Standard

isNaN()
calling isNaN on something, checks if that thing is not a number

isNaN(“banana”);
// true

isNaN(NaN);
// true

isNaN(undefined);
// true

isNaN(42);
// false

but calling isNaN on a string that looks like a number, like “42”, javascript will try to help by automatically converting the string to the number 42 and return false (since 42 is a number)

this syntax can’t be used if the variable hasn’t been declared earlier
isNaN(dogs);

JS LOOPS

Standard

ciclo while con counter i
var loopThree = function(){
i = 0;
while(i < 3){
console.log(“I’m looping”);
i++;
}
};

loopThree();

ciclo while con validazione booleana
soloLoop()
var soloLoop = function(){
while(bool === true){
console.log(“looped once”);
bool = false
}
};

bool = true;
soloLoop();

ma il while loop si usa preferibilmente quando non si sa quante volte è necessario ripetere la stessa operazione.

la moneta viene lanciata finché non è uguale a 1
var coinFace = Math.floor(Math.random() * 2);

while(coinFace === 0){
console.log(“heads, flipping again”);
var coinFace = Math.floor(Math.random() * 2);
}
console.log(“tails, done flipping”);

differenza di sintassi tra while e for
var loop = function(){
// if(bool) is the abbreviation of if(bool===true)
while(bool){
console.log(“qualcosa”);
bool = false;
}
}
bool = true;
loop();

// for loop
for(i=0;i<1;i++){
console.log(“qualcosa”);
}

ciclo do, while
var loopCondition = false;

do {
console.log(“smetto di loopare perché la mia loop condition è ” + loopCondition);
} while (loopCondition);

all together
// while loop
var whileLoop = function(bool){
while(bool){
console.log(“bool is true”);
bool = false;
}
}

whileLoop(true);

// do, while loop
var doWhileLoop = function(bool){
do {
console.log(“I log even if bool is false”);
} while(bool);
}

doWhileLoop(false);

// for loop
var forLoop = function(){
for(i=0; i<1; i++){
console.log(“I log only one time”);
}
}

forLoop();

jsLoops

JS FIND NAME IN ARRAY

Standard

una stringa può essere trattata come un array di caratteri
var myArray = [“ciao”, “mondo”];
console.log(myArray[0]);
// “ciao”

la stessa logica funziona per le stringhe
var myName = “Giada”
console.log(myName[0]);
// “G”

il metodo push() aggiunge ciò che c’è nelle parentesi alla fine dell’array a cui viene applicato
myArray = [ ];
myArray.push(“ciao”);
console.log(myArray[0]);
// “ciao”

jsFindNameInArray

PHP HEADER()

Standard

the header() method sends a raw http header
header() must be called before any actual output is sent, either by normal HTML tags, blank lines in a file, or from PHP
it is an error to read code with include, or require, functions, or another file access function, and have spaces or empty lines that are output before header() is called
the same problem exists when using a single PHP/HTML file

<html>
<?php
// this will give an error, because the <html> tag is placed before the header() call
header(‘Location: http://www.example.com/&#8217;);
exit;
?>

there are two special-case header calls:

header(“HTTP/1.0 404 Not Found”);

the first is a header that starts with the string “HTTP/”, which will be used to figure out the HTTP status code to send
for example, if APACHE has been configured with a PHP script to handle requests for missing files (using the ErrorDocument directive), you may want to make sure that your script generates the proper status code

header(“Location: http://www.example.com/&#8221;);
the second special case is the “Location:” header, that sends this header back to the browser and also returns a REDIRECT (302) status code to the browser unless the 201 or a 3xx status code has already been set

per fare un redirect PHP è necessario utilizzare la funzione header()
questa è una funzione nativa del PHP, mediante la quale possiamo inviare intestazioni HTTP al client che sta visitando la nostra pagina web, è possibile impostare una nuova location verso la quale reindirizzare la navigazione dell’utente, in poche parole possiamo far “rimbalzare” l’utente portandolo su un’altra pagina del nostro o di un altro sito

effettuare un redirect automatico dell’utente verso una diversa pagina del sito o di un sito differente
// redirect verso pagina interna
header(“location: /nuova-pagina.php”);

// redirect verso una risorsa esterna al sito
header(“location: http://www.sito.it/pagina.php&#8221;);

l’uso di questo codice deve essere fatto prima di aver generato alcun output, altrimenti l’interprete PHP restituirà un errore
echo “print it before the redirect”;
header(“location: http://www.sito.it/pagina.php&#8221;);
// error

dopo l’uso della funzione header(), bisogna inserire un exit se all’interno dello script c’è altro codice da eseguire dopo quello che fa il redirect

if ($utente_loggato == false) {
header(“location: http://www.sito.it/pagina.php&#8221;);
exit;
}
// segue altro codice php