Archivi tag: mysql

Script bash per automatizzare le query su MySQL

Scenario

Supponiamo che il vostro DBMS (MySQL) stia gestendo più database e che sia necessario effettuare delle query  “a tappeto”, ovvero su tutte le tabelle relative a ciascuno di essi (cercando, ad esempio, un determinato record oppure un pattern specifico).

bashEseguire tale operazione “a mano” può essere tedioso e soprattutto controproducente in termini di tempo. Come fare quindi? Semplice, realizzare uno scrip bash in grado di automatizzare tale attività.

Ecco il codice:

#!/bin/bash

mysql -u utente -ppassword -e 'show databases' | grep -v Database | grep -v information_schema | grep -v mysql > databases

while read line
do

        command="mysql -u utente -ppassword -e 'use $line; show tables'"
        eval $command | grep -v "Tables_in_*" > tables_$line

done < databases

num_databases=`cat databases | wc -l`

ls | grep "tables_*" > table

num_tables=`cat table | wc -l`

if [ $num_databases -eq $num_tables ];then

        for i in {1..19}
        do
                database=`cat databases | sed -n "$i p"`
                echo ".......tables for $database......."
                cat tables_"$database" | while read line
                do
                        echo $line
                        command="mysql -u utente -ppassword -e 'use $database; select * from $line LIMIT 1'"
                        echo "....Executing $command...." >> result
                        eval "$command" | tee -a result
                        echo "....End executing $command ...." >> result

                done
                echo ".......end tables for $database......."
        done

fi

Per prima cosa identifico tutti i database definiti su MySQL, escludendo quelli di default (mysql ed information_schema), formattando opportunamente l’output ( grep -v Database) e salvando i risultati all’interno del file databases:

mysql -u utente -ppassword -e 'show databases' | grep -v Database | grep -v information_schema | grep -v mysql > databases

Successivamente listo le tabelle presenti in ciascun database mediante un ciclo while che legge, riga per riga, il contenuto del file databases e, per ognuna, esegue il comando show tables:

while read line
do

        command="mysql -u utente -ppassword -e 'use $line; show tables'"
        eval $command | grep -v "Tables_in_*" > tables_$line

done < databases

Da notare come la stringa $command venga dapprima definita in modo tale da contenere il valore della variabile $line e successivamente venga eseguita sottoforma di comando mediante la direttiva eval.

Verifico, quindi, che il numero dei file tables_$line sia uguale al numero di database (e che quindi vi sia la ragionevole certezza che per ciascun database sia stato individuato il nome delle tabelle di cui è composto):

num_databases=`cat databases | wc -l` ls | grep "tables_*" > table 

num_tables=`cat table | wc -l` 

if [ $num_databases -eq $num_tables ];then

Infine, per ciascuna tabella di ciascun database, lancio la query mysql -u utente -ppassword -e ‘use $database; select * from $line LIMIT 1’, definita come stringa ed eseguita mediante eval (come visto in precedenza):

for i in {1..19}
        do
                database=`cat databases | sed -n "$i p"`
                echo ".......tables for $database......."
                cat tables_"$database" | while read line
                do
                        echo $line
                        command="mysql -u utente -ppassword -e 'use $database; select * from $line LIMIT 1'"
                        echo "....Executing $command...." >> result
                        eval "$command" | tee -a result
                        echo "....End executing $command ...." >> result

                done
                echo ".......end tables for $database......."
        done

fi

Da notare come, nel mio caso, vi sia un totale di 19 database, per cui ho utilizzato un semplice ciclo for così definito:

for i in {1..19}

Nulla però vieta di usare come upper bound la variabile $num_databases o $num_tables.

Infine rendiamo eseguibile lo scrip (che ho denominato, per semplicità, my.sh):

[root@server ~]# chmod +x my.sh

ed eseguiamolo:

[root@server ~]# ./my.sh

E’ tutto, alla prossima.

CentOS 6: realizzare un network intrusion detection system open source – Parte 3

Dopo aver installato e configurato snort, barnyard2, pulledpork e MySQL (vedi qui e qui), ora vedremo come installare l’interfaccia Web del nostro sistema NIDS, ovvero Snorby.

Poichè tale interfaccia si basa su Ruby, è necessario predisporre il nostro sistema per il supporto del linguaggio di scripting in questione.

snorby-dashboard

Preparazione della macchina

Per prima cosa installiamo i software prerequisiti, mediante i comandi:

yum -y groupinstall "Development Tools"

yum install -y openssl-devel readline-devel libxml2-devel libxslt-devel mysql mysql-devel mysql-libs mysql-server urw-fonts libX11-devel libXext-devel qconf fontconfig-devel libXrender-devel unzip

yum -y install xz urw-fonts libXext openssl-devel libXrender

Successivamente, scarichiamo ed installiamo ImageMagick , per la creazione di immagini bitmap, e wkhtmltopdf, per la conversione delle pagine HTML in PDF (funzionalità indispensabile durante la generazione dei report):

cd /usr/local/src

wget ftp://ftp.fifi.org/pub/ImageMagick/ImageMagick-6.8.9-6.tar.gz

tar -xvf ImageMagick-6.8.9-6.tar.gz

cd ImageMagick-6.8.9-6

./configure

make

make install

ldconfig 

cd ..

wget http://sourceforge.net/projects/wkhtmltopdf/files/0.12.1/wkhtmltox-0.12.1_linux-centos6-amd64.rpm/download

rpm -Uvh wkhtmltox-0.12.1_linux-centos6-amd64.rpm

Adesso scarichiamo rvm, attraverso il quale sarà possibile installare la versione di Ruby compatibile con Snorby (ovvero la 1.9.3, che, purtroppo, è ormai obsoleta e non più mantenuta):

curl -L get.rvm.io | bash -s stable

Installiamo dunque Ruby e facciamo in modo che il sistema utilizzi la versione 1.9.3 come default:

rvm install 1.9.3

rvm use --default 1.9.3

Ora, utilizzando il packet manager di Ruby (ovvero gem), procediamo con l’installazione di Rails (il framework) e di passenger (necessario per integrare Snorby e Apache):

gem install rails

gem install passenger

passenger-install-apache2-module

Installiamo alcuni pacchetti prerequisiti:

gem install devise_cas_authenticatable -v '1.1.0'

e

gem install bundler

In particolare, quest’ultimo si occupa di gestire le dipendenze tra i gem (ed è il software responsabile della creazione dei file Gemfile e Gemfile.lock).

Installazione e configurazione di Snorby

Creiamo la directory nella quale ospitare Snorby:

mkdir -p /var/www/html/snorby

e scarichiamo l’applicazione vera e propria:

cd /var/www/html/snorby

wget -O snorby.zip --no-check-certificate https://github.com/Snorby/snorby/archive/master.zip

Scompattiamo l’archivio, posizioniamoci nella directory snorby-master e spostiamone il contenuto all’interno di /var/www/html/snorby:

unzip snorby.zip

cd snorby-master/

mv * ../

Modifichiamo ora il contenuto del file Gemfile, sostituendo le direttive di default per rake, json e devise_cas_authenticatable con le seguenti:

gem 'rake', '0.9.2.2'
gem 'json', '~> 1.8.3'
gem 'thin'

gem 'devise_cas_authenticatable',  '~> 1.1.0'

Inoltre, è necessario inserire la direttiva gem ‘thin’ subito dopo gem ‘json’, commentando quella dopo gem “letter_open”:

gem 'json', '~> 1.8.3'
gem 'thin'

group(:development) do
     gem "letter_opener"
   # gem 'thin'

Discorso simile vale per il file Gemfile.lock, in cui bisogna modificare le direttive rake e json nel seguente modo:

rake (0.9.2.2)

json (1.8.3)

Lanciamo il comando bundle install in modo da installare i pacchetti gem (con le relative dipendenze) definiti all’interno del Gemfile precedentemente editato:

bundle install

Eliminiamo la dir snorby-master (ormai vuota) e passiamo alla configurazione di Snorby:

rm -rf snorby-master/

cd config

cp snorby_config.yml.example snorby_config.yml

nano snorby_config.yml

definendo la giusta timezone:

time_zone: Europe/Rome

A questo punto possiamo configurare la connessione al database, editando il file config/database.yml:

cd ..

cp config/database.yml.example config/database.yml

nano config/database.yml

il cui contenuto sarà simile al seguente:

# Snorby Database Configuration
#
# Please set your database password/user below
# NOTE: Indentation is important.
#
snorby: &snorby
  adapter: mysql
  username: vostrouser
  password: "vostrapassword" # Example: password: "s3cr3tsauce"
  host: localhost

development:
  database: snorby
  <<: *snorby

test:
  database: snorby
  <<: *snorby

production:
  database: snorby

Avviamo l’applicazione (con finalità di test), mediante i comandi:

rake snorby:setup

rails server thin -e production

da lanciare all’interno della dir /var/www/html/snorby ed il cui output dovrebbe essere simile al seguente:

=> Booting Thin
=> Rails 3.1.12 application starting in production on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
Thin web server (v1.6.3 codename Protein Powder)
Maximum connections set to 1024
Listening on 0.0.0.0:3000, CTRL+C to stop

http://ip:3000/users/login

Provando ora a connetterci (con il nostro browser) a http://ip:3000/users/login dovremmo riuscire a visualizzare l’interfaccia di Snorby (con il relativo form per il login, dove l’email di default è snorby@example.com e la password è semplicemente snorby).

Integrazione tra Snorby e Apache

Come già affermato in precedenza, il modulo di Apache che consente al nostro server Web di interfacciarsi con le applicazioni scritte in Ruby prende il nome di passenger.

Per prima cosa occorre dunque configurare il suddetto modulo:

nano /etc/httpd/conf.d/mod_passenger.conf

il cui contenuto dovrà essere:

LoadModule passenger_module /usr/local/rvm/gems/ruby-1.9.3-p551/gems/passenger-5.0.16/buildout/apache2/mod_passenger.so

PassengerRoot /usr/local/rvm/gems/ruby-1.9.3-p551/gems/passenger-5.0.16
PassengerDefaultRuby /usr/local/rvm/gems/ruby-1.9.3-p551/wrappers/ruby

Infine, modifichiamo il file di configurazione di Apache (/etc/httpd/conf/httpd.conf), creando un virtual host opportuno (in ascolto sulla porta TCP 82):

Listen 82

<VirtualHost *:82>
     Servername vostroserver.vostrodominio.com
     DocumentRoot /var/www/html/snorby/public
     <Directory /var/www/html/snorby/public>
        Order deny,allow
        Allow from all
        Options -MultiViews
        AuthName "Snorby Access"
        AuthType Basic
        AuthUserFile /etc/snorby/passwd
        Require valid-user
    </Directory>
</VirtualHost>

Tale virtual host richiede l’autentica HTTP, ergo occorre creare il file in cui verranno salvate le coppie username/password da utilizzare:

mkdir -p /etc/snorby

htpasswd -c /etc/snorby/passwd vostroutente

Infine, riavviamo Apache:

service httpd reload

ed abbiamo finito.

Alla prossima.

CentOS 6: realizzare un network intrusion detection system open source – Parte 2

In questo post ho mostrato come configurare il software che funge da sensore, ovvero snort. Adesso vedremo come installare e configurare pulledpork (che si occuperà dell’aggiornamento delle firme) e barnyard2 (per il salvataggio degli allarmi all’interno di un DB).

Barnyard2Installazione e configurazione di pulledpork

Per prima cosa occorre installare i prerequisiti, ovvero perl-libwww-perl perl-Crypt-SSLeay e perl-Archive-Tar:

yum -y install perl-libwww-perl perl-Crypt-SSLeay perl-Archive-Tar

Posizioniamoci nella dir /usr/local/src  e scarichiamo l’applicativo in questione (scritto in Perl):

wget https://pulledpork.googlecode.com/files/pulledpork-0.7.0.tar.gz

per poi scompattare l’archivio, rendere lo scrip eseguibile e copiarlo all’interno di /usr/sbin (assegnandogli i giusti privilegi):

tar -xvf pulledpork-0.7.0.tar.gz
cd pulledpork-0.7.0
chmod +x pulledpork.pl
cp pulledpork.pl /usr/sbin
chmod 755 /usr/sbin/pulledpork.pl

A questo punto possiamo copiare i file *.conf (presenti nella directory etc) all’interno di /etc/snort, con il successivo editing dei permessi:

cd etc
cp * /etc/snort
chown -R snort:snort /etc/snort

Ora modifichiamo il contenuto del file /etc/snort/pulledpork.conf, apportando le seguenti modifiche:

snort_path=/usr/sbin/snort
config_path=/etc/snort/snort.conf
distro=Centos-5-4
rule_path=/etc/snort/rules/snort.rules
out_path=/etc/snort/rules/
sid_msg=/etc/snort/sid-msg.map
black_list=/etc/snort/rules/black_list.rules
#IPRVersion=/usr/local/etc/snort/rules/iplists
enablesid=/etc/snort/enablesid.conf
dropsid=/etc/snort/dropsid.conf
disablesid=/etc/snort/disablesid.conf
modifysid=/etc/snort/modifysid.conf

rule_url=https://www.snort.org/reg-rules/|snortrules-snapshot-2975.tar.gz|<vostro oinkcode>
rule_url=https://s3.amazonaws.com/snort-org/www/rules/community/|community-rules.tar.gz|Community
rule_url=http://labs.snort.org/feeds/ip-filter.blf|IPBLACKLIST|open
rule_url=https://www.snort.org/reg-rules/|opensource.gz|<vostro oinkcode>

Da notare che ho commentato la direttiva IPRVersion ed ho scelto un nome specifico per le blacklist (ovvero black_list.rules), in quando devono essere differenziate da quelle utilizzate da snort (reputation preprocessor). Per la precisione, il file black_list.rules non è altro che una lista piatta di indirizzi IP, a differenza del file blacklist.rules che possiede il tipico formato delle regole di snort (ad esempio alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS).

Testiamo adesso la configurazione di pulledpork mediante il comando:

pulledpork.pl -vv -c /etc/snort/pulledpork.conf -T -l

e se il relativo output contiene la stringa:

Fly Piggy Fly!

vuol dire che il suddetto applicativo sta funzionando correttamente. Creaiamo un task su crontab per eseguire l’update delle firme ogni notte:

nano /etc/crontab

il cui contenuto dovrà essere:

00 04 * * * root /usr/sbin/pulledpork.pl -c /etc/snort/pulledpork.conf && /sbin/service snortd restart

e passiamo alla configurazione di barnyard2.

Installazione e configurazione di barnyard2

Prima di cominciare occorre fare una premessa: il file di configurazione che daremo in pasto a barnyard2 può riferirsi ad una sola interfaccia. Ciò significa che dovremo creare un file di configurazione specifico per ciascuna interfaccia su cui i sensori (le istanze di snort) sono in ascolto, in modo tale che il loro output possa essere parsato (in modo indipendente) dalle due istanze distinte di barnyard2.

Come al solito, il primo step consiste nell’installazione del software necessario per la compilazione del suddetto applicativo:

yum install libtool

e successivamente, dopo esserci posizionati nella directory /usr/local/src, possiamo scaricare i sorgenti:

cd /usr/local/src
git clone git://github.com/firnsy/barnyard2.git

Compiliamo ed installiamo:

cd barnyard2
./autogen.sh
./configure --with-mysql --with-mysql-libraries=/usr/lib64/mysql/
make
make install

copiamo il file di configurazione di barnyard2 all’interno della directory /etc/snort

cp etc/barnyard2.conf /etc/snort

e modifichiamolo in base alle nostre esigenze:

config logdir: /var/log/snort
config interface:  eth0
config daemon
input unified2
output alert_full
config waldo_file: /var/log/snort/eth0/barnyard2-log.waldo
output log_tcpdump: tcpdump.log
output database: log, mysql, user=<vostrouser> password=<vostrapassword> dbname=snorby host=localhost

copiamo il suddetto file in barnyard2-eth0.conf ed in barnyard2-eth1.conf:

cp /etc/snort/barnyard2.conf /etc/snort/barnyard2-eth0.conf

cp /etc/snort/barnyard2.conf /etc/snort/barnyard2-eth1.conf

Modifichiamo quest’ultimo sostituendo le diciture:

config interface:  eth0

config waldo_file: /var/log/snort/eth0/barnyard2-log.waldo

con:

config interface:  eth1

config waldo_file: /var/log/snort/eth1/barnyard2-log.wald

Inoltre, per fare in modo che le due istanze di barnyard2 vengano avviate come “demone”, ho modificato il file di startup presente nella dir rpm, dopo averlo copiato in /etc/init.d ed averlo reso eseguibile:

cp rpm/barnyard2 /etc/init.d
chmod +x /etc/init.d/barnyard2

Di seguito riporto il contenuto del suddetto file, in cui sono presenti le modifiche da me effettuate:

#!/bin/sh
#
# Init file for Barnyard2
#
#
# chkconfig: 2345 60 60
# description:  Barnyard2 is an output processor for snort.
#
# processname: barnyard2
# config: /etc/sysconfig/barnyard2
# config: /etc/snort/barnyard.conf
# pidfile: /var/lock/subsys/barnyard2.pid

source /etc/rc.d/init.d/functions
source /etc/sysconfig/network

### Check that networking is up.
[ "${NETWORKING}" == "no" ] && exit 0

[ -x /usr/sbin/snort ] || exit 1
[ -r /etc/snort/snort.conf ] || exit 1

### Default variables
SYSCONFIG="/etc/sysconfig/barnyard2"

### Read configuration
[ -r "$SYSCONFIG" ] && source "$SYSCONFIG"

RETVAL=0
prog="barnyard2"
desc="Snort Output Processor"

start() {
        echo -n $"Starting $desc ($prog): "
        for INT in $INTERFACES; do
                echo " "
                echo "binding over $INT..."
                ARCHIVEDIR="$SNORTDIR/$INT/archive"
                WALDO_FILE="$SNORTDIR/$INT/barnyard2.waldo"
                if [ $INT == 'eth0' ];then
                BARNYARD_OPTS="-D -c $CONF1 -d $SNORTDIR/${INT} -w $WALDO_FILE -l $SNORTDIR/${INT} -a $ARCHIVEDIR -f $LOG_FILE $EXTRA_ARGS"
                elif [ $INT == 'eth1' ];then
                BARNYARD_OPTS="-D -c $CONF2 -d $SNORTDIR/${INT} -w $WALDO_FILE -l $SNORTDIR/${INT} -a $ARCHIVEDIR -f $LOG_FILE $EXTRA_ARGS"
                fi
                daemon $prog $BARNYARD_OPTS
        done
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$prog
        return $RETVAL
}

stop() {
        echo -n $"Shutting down $desc ($prog): "
        killproc $prog
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ] && rm -f /var/run/barnyard2*
        return $RETVAL
}

restart() {
        stop
        start
}

reload() {
        echo -n $"Reloading $desc ($prog): "
        killproc $prog -HUP
        RETVAL=$?
        echo
        return $RETVAL
}

case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  restart)
        restart
        ;;
  reload)
        reload
        ;;
  condrestart)
        [ -e /var/lock/subsys/$prog ] && restart
        RETVAL=$?
        ;;
  status)
        status $prog
        RETVAL=$?
        ;;
  dump)
        dump
        ;;
  *)
        echo $"Usage: $0 {start|stop|restart|reload|condrestart|status|dump}"
        RETVAL=1
esac

exit $RETVAL

Il contenuto del file /etc/sysconfig/barnyard2 (in cui sono contenute le opzioni di avvio del demone) è, invece, il seguente:

LOG_FILE="snort.log"
SNORTDIR="/var/log/snort"
INTERFACES="eth0 eth1"
PIDPATH="/var/run"
CONF1=/etc/snort/barnyard2-eth0.conf
CONF2=/etc/snort/barnyard2-eth1.conf
EXTRA_ARGS="--pid-path /var/run"

Creiamo i file con estenzione *.waldo:

touch /var/log/snort/eth0/barnyard2-log.waldo

touch /var/log/snort/eth1/barnyard2-log.waldo

e facciamo in modo che il suddetto demone venga avviato in modo automatico dopo ogni riavvio della macchina:

chkconfig --add barnyard2

chkconfig barnyard2 on

Creaiamo ora il DB snorby (in cui barnyard2 dovrà salvare gli allarmi generati da snort) attraverso l’interfaccia a linea di comando di MySQL. I comandi da lanciare sono i seguenti:

create schema snorby;
grant all on snorby.* to vostrouser@localhost;
set password for vostrouser@localhost=password('vostrapassword');
use snorby;
source /usr/local/src/barnyard2/schemas/create_mysql
flush privileges;
exit

Prima di avviare il suddetto demone, occorre verificare che la sua priorità di avvio minore rispetto a quella di MySQL (valori bassi corrispondono a priorità alte). Infatti, in caso contrario, barnyard2 tenterà di parlare (via file mysql.sock) con il DBMS in questione, cosa impossibile nel caso in cui MySQL non sia ancora avviato (restituendoci, molto banalmente, l’errore file not found). In particolare, all’interno del codice associato al demone barnyard2 (da me modificato), è presente una priorità di avvio pari a 60 (definita tramite la direttiva chkconfig), mentre, a titolo di cronaca, la priorità di avvio relativa al demone mysqld è pari a 49.

Verifichiamo che tutto funzioni correttamente mediante i comandi:

barnyard2 -c /etc/snort/barnyard2-eth0.conf -d /var/log/snort/eth0 -f snort.log -w /var/log/snort/barnyard2-log.waldo -D

e

barnyard2 -c /etc/snort/barnyard2-eth1.conf -d /var/log/snort/eth1 -f snort.log -w /var/log/snort/barnyard2-log.waldo -D

per poi avviare il demone vero e proprio:

service barnyard2 start

A demone avviato, come ulteriore verifica, possiamo collegarci al DB snorby e lanciare la query:

select count(*) from events;

e se il valore restituito è > 0 vuol dire che barnyard2 e snort stanno operando correttamente.

Per ora è tutto. Nel prossimo post vedremo come installare e configurare Snorby (la Web GUI).

CentOS 6: Watchdog open source mediante Monit

Premesso che Monit può essere configurato anche come NMS a tutti gli effetti (sia centralizzato che distribuito, vedi M/Monit), lo scopo di questo post è quello di illustrarne la configurazione come semplice watchdog.

watchdogEsso, infatti, si occuperà di riavviare eventuali servizi “in stallo” (nella fattispecie httpd e mysql), riducendo notevolmente i tempi di downtime.

Per prima cosa occorre installare il suddetto applicativo:

[root@server ~]# yum install monit

Una volta installato possiamo editarne la configurazione (/etc/monit.conf) nel modo seguente:

set httpd port 2813 and #2813 è la porta su cui è in ascolto l'interfaccia Web di Monit
     use address <indirizzo IP>  #l'indirizzo IP è quello su cui l'interfaccia Web di Monit è in binding
     allow 0.0.0.0/0          #semplice ACL per consentire a qualunque IP sorgente di connettersi alla suddetta interfaccia  
     allow username:password      # credenziali di accesso all'interfaccia Web di Monit
     allow @monit           
     allow @users readonly

A questo punto creiamo due file all’interno della directory /etc/monit.d, rispettivamente httpd e mysqld.

Il primo conterrà le seguenti direttive:

check process httpd with pidfile /var/run/httpd.pid
group apache
start program = "/etc/init.d/httpd start"
stop program = "/etc/init.d/httpd stop"
if failed host 94.23.68.182 port 80
protocol http then restart
if 5 restarts within 5 cycles then timeout

Il secondo, invece, avrà il seguente contenuto:

check process MySQL-Server with pidfile /var/run/mysqld/mysqld.pid
    start program = "/etc/init.d/mysqld start"
    stop program = "/etc/init.d/mysqld stop"
    if failed host localhost port 3306
    protocol mysql then restart
    if 5 restarts within 5 cycles then timeout

Verifichiamo la sintassi delle suddette configurazioni mediante il comando:

[root@server ~]# monit -t

Ora possiamo avviare il nostro watchdog:

[root@server ~]# service monit start

imponendone l’avvio automatico dopo ogni reboot del server:

[root@server ~]# chkconfig monit on

Verifichiamo l’effettiva raggiungibilità dell’interfaccia Web di Monit mediante la URL:

http://IP:2813

ed il gioco è fatto.

E’ tutto. Alla prossima.

Installare MySQL da sorgenti

Chiunque abbia mai avuto a che fare con Linux conoscerà sicuramente i cosiddetti packet manager (yum, aptitude, emerge, ecc.). Utilizzandoli insistentemente si rischia di non sapere più come comportarsi nel caso in cui sia necessario installare una vecchia versione di un pacchetto software, oppure una versione beta dello stesso (non presente nei repositories).

 

My.jpg

La prima scelta, solitamente, ricade sui pacchetti precompilati per una specifica architettura hardware ed un sistema operativo ben determinato. Quando questi pacchetti non sono disponibili (a.k.a. Gentoo), è necessario scaricare i file sorgenti e compilare il tutto a manetta.

Dopo questa breve introduzione, vi mostrerò come installare MySQL 5.0.91 su Gentoo. Tale procedura vale per tutte le versioni di MySQL che necessitano di compilazione manuale. Ma bando alle ciance e veniamo al dunque.

Per prima cosa creiamo la directory in cui verrà installato il pacchetto in questione:

nightfly@nightbox:~$ mkdir /usr/local/mysql

Adesso, dopo aver scaricato mediante wget la tarball contenente i sorgenti di MySQL, possiamo procedere con la loro compilazione ed installazione:

 nightfly@nightbox:~$ tar -xvf mysql-5.0.91.tar.gz
 nightfly@nightbox:~$ cd mysql-5.0.91
 nightfly@nightbox:~$ ./configure --prefix=/usr/local/mysql
 nightfly@nightbox:~$ make
 nightfly@nightbox:~$ make install

Aggiungiamo l’utente mysql che useremo per avviare il demone e modifichiamo l’owner della directory target:

 nightfly@nightbox:~$ chown mysql:mysql /usr/local/mysql
 nightfly@nightbox:~$ cd /usr/local/mysql/bin

Installiamo i DB di default:

nightfly@nightbox:~$ ./mysql_install_db

Copiamo il file di configurazione di MySQL su /etc:

nightfly@nightbox:~$ cp /usr/local/mysql/share/mysql/my-medium.cnf  /etc
 nightfly@nightbox:~$ mv /etc/my-medium.cnf /etc/my.cnf

Copiamo gli eseguibili in /usr/local/sbin:

nightfly@nightbox:~$ cp /usr/local/mysql/bin /usr/local/sbin

Verifichiamo che la copia sia andata a buon fine:

nightfly@nightbox:~$ which mysql

Copiamo il demone in /etc/init.d e rinominiamolo in mysqld:

 nightfly@nightbox:~$ cp /usr/local/mysql/share/mysql/mysql.server /etc/init.d
 nightfly@nightbox:~$ cd /etc/init.d
 nightfly@nightbox:~$ mv mysql.server mysqld

Avviamo il demone e verifichiamo che sia attivo mediante un netstat ed un ps:

nightfly@nightbox:~$ /etc/init.d/mysqld start

nightfly@nightbox:~$ netstat -anp | grep :3306
nightfly@nightbox:~$ ps aux | grep mysqld

A questo punto possiamo definire la password per l’utente root digitando:

nightfly@nightbox:~$ mysqladmin -u root password <password>

L’ultima cosa da fare consiste nella definizione delle ACL di accesso ai DB. Un esempio di ACL è il seguente:

mysql> GRANT ALL ON *.* TO root IDENTIFIED BY 'rootpassword';

ovvero sto definendo il permesso (GRANT) di effettuare INSERT, UPDATE, DELETE e SELECT (ALL) su tutte le tabelle (*) di tutti i DB presenti (.*).

Come ultima verifica proviamo ad accedere a MySQL da locale e da remoto, lanciando il comando:

nightfly@nightbox:~$mysql -u root -prootpassword

(da locale);

nightfly@nightbox:~$mysql -h <hostname> -u root -prootpassword

(da remoto).

Se i tentativi di connessione vanno a buon fine vuol dire che il nostro DBMS è stato installato correttamente ed è pronto per l’uso.

A presto.

PHP e mysql: input sanitization di base

Tutti gli addetti ai lavori sanno (o almeno dovrebbero sapere) che nell’ambito della sicurezza Web occorre prestare particolare attenzione ai dati trasmessi al server mediante gli appositi form HTML.

Tale operazione si rende indispensabile poichè un utente malevolo potrebbe “postare” delle stringhe “ad hoc” per “iniettare” del codice SQL arbitrario (SQL injection) oppure inserire all’interno della pagina del codice HTML (o javascrip) che provoca il reindirizzamento su un sito infetto (iframe, redirect et similia, ovvero tutto ciò che riguarda gli attacchi XSS).

background_xss.gif

Per questo motivo ho deciso di postare qualche riga di codice PHP che consente di filtrare in modo rapido ed efficace i dati immessi dagli utenti.

In particolare, vengono svolti due controlli: il primo si occupa dell’individuazione (e la successiva rimozione) dei caratteri speciali di MySQL (apice singolo, apice doppio, backslash, cancelletto, ecc.), mentre il secondo verifica che non vi siano dei tag HTML all’interno delle stringhe immesse nei campi di input.

Ecco il codice:

if(isset($_POST['username']) && $_POST['username'] != '')
{
$username = mysqli_real_escape_string($mysqli,strip_tags($_POST['username']));
}

else
{
        $errore = 'Devi inserire lo username';
}

Come potete notare, il campo su cui è stato implementato il filtro è quello relativo allo username. Per prima cosa viene verificato che la variabile $_POST[‘username’] sia settata e non sia vuota.

Se tale controllo va a buon fine, tramite la funzione strip_tags() viene rimosso l’eventuale codice HTML e successivamente, mediante mysqli_real_escape_string() vengono filtrati i caratteri speciali relativi a MySQL.

Ovviamente, attraverso tale meccanismo non darete agli utenti la possibilità di scegliere username del tipo:

<username>

o ancora:

username#

ma si sa, in questi casi bisogna certamente scendere a compromessi e capire dove sta il male minore.

A presto.

Visualizzare mediante PHP il nome del database utilizzato

Recentemente ho dovuto modificare parzialmente uno dei CRM che ho sviluppato. Non volendo inficiare il DB in produzione ho dovuto “clonarlo”, in modo da poter fare i miei esperimenti in assoluta libertà.

Poichè volevo essere sicuro che ciascuna pagina utilizzasse effettivamente il database “clone” (avendo a disposizione un solo server), ho implementato un controllo in PHP che mi restituisse il nome del DB in uso all’apertura della pagina.

Ecco lo scrip:

$db = $mysqli -> query("SELECT DATABASE()");

while($riga1 = $db -> fetch_assoc())
{
    echo $riga1["DATABASE()"];
}

La chiave di lettura delle righe di codice sopra riportate sta proprio nella funzione DATABASE() di MySQL, la quale consente di individuare il nome del DB in uso.

Da riga di comando avremo una situazione simile alla seguente:

mysql> SELECT DATABASE();
+------------+
| DATABASE() |
+------------+
| prova        |
+------------+
1 row in set (0.00 sec)

mysql>

Il post termina qui, a presto.

Script per il backup giornaliero di un database remoto

Visto che la ridondanza non è mai troppa (Murphy vi dice qualcosa?), ho pensato di realizzare uno scrip per effettuare il backup di un database hostato su un server remoto.

shell

Ecco lo scrip (basato su expect):

#!/usr/bin/expect -f
set date [exec date +%d_%m_%y]
set password1 "<pass1>"
set password2 "<pass2>"
set database "<nomedb>"
spawn ssh user@hostname
expect "*?assword:*"
send "$passwordr"
send "r"
expect ":~$"
send "mysqldump $database -u root -ppassvostrodb > $database_$date.plr"
send "$database_$date.pl user@hostname:/home/userr"
expect "*?assword:*"
send "$password2r"
send "r"
expect ":~$"
send "rm database_*r"
expect eof

Lo scrip in questione si collega via SSH al server remoto, esegue un dump del database per poi copiarlo tramite SCP sul mio server.

Affinchè tale scrip venga eseguito giornalmente (per la precisione ogni sera alle 22) è necessario editare il file /etc/crontab aggiungendo la seguente direttiva:

00 22   * * * user  cd /home/user/ && ./backupremotedb > /dev/null 2>&1

Per ulteriori info contattatemi.

A presto.

Script bash per l’invio di notifiche tramite email

Poco tempo fa ho deciso di creare un piccolo scrip in grado di interrogare un database, salvare temporaneamente in un file la risposta alla query ed inviare una notifica via email all’indirizzo di posta specificato. Nella fattispecie, tale scrip ha come scopo principale quello di notificare le scadenze da saldare e quelle non rispettate.

bash,mail,email,mysql,query,script,scadenze,notifiche

Ma bando alle ciance ed ecco lo scrip:

#!/bin/bash

destinatario=vostro.indirizzo@email.it

logfile=/var/log/notifier.log

ROOT_UID=0

data=`date +%s` #lavoro con i timestamp per poter confrontare le date

if [ "$UID" -ne "$ROOT_UID" ];then

        ERRORE1="Errore 1: Devi essere root per eseguire lo scrip"
        echo $ERRORE1
        echo "$(date) $ERRORE1" >> $logfile

        exit 1

fi

mysql -u root -ppassword -D nomedb -e "SELECT * FROM scadenza;" >> scadenze

echo "Hai le seguenti scadenze da saldare: " > scadenze_imminenti;

echo "Hai le seguenti scadenze non saldate: " > scadenze_nonrispettate;

while read line

do

        scad=`cat scadenze | grep - | awk '{print $2}'` #per individuare la data di scadenza.

        for info in $scad

        do

                datascad=`date --utc --date "$info" +%s`  #uso i timestamp per confrontare le date

                if [ "$data" -le "$datascad" ];then

                        if [[ $line =~ $info --;then

                                echo $line >> scadenze_imminenti

                        fi

                fi

                if [ "$data" -gt "$datascad" ];then

                        if [[ $line =~ $info --;then

                                echo $line >> scadenze_nonrispettate

                        fi
                fi

       done

done < scadenze

if grep -q "-" scadenze_imminenti ;then

uniq scadenze_imminenti | mail -iv -s "Scadenze da saldare" $destinatario;

fi

if grep -q "-" scadenze_nonrispettate ;then

uniq scadenze_nonrispettate | mail -iv -s "Scadenze non saldate" $destinatario;

fi

rm scadenze

rm scadenze_imminenti

rm scadenze_nonrispettate

exit 0

Come è facile notare, viene fatto un confronto tra la data corrente e quella di ciascuna scadenza (sottoforma di UNIX timestamp). Nel caso in cui la data corrente sia antecedente o uguale a quelle delle scadenze, esse verranno salvate nel file scadenze_imminenti, il cui contenuto verrà successivamente inserito nel corpo di una email e spedito al destinatario.

Invece, se la data attuale è maggiore di quella della scadenza, quest’ultima verrà salvata nel file scadenze_nonrispettate, il cui contenuto verrà recapitato nella casella email del destinatario.

Per qualsiasi chiarimento contattatemi.

Bye.

MySQL: identificare la tabella da cui provengono i dati ricavati mediante una UNION di due SELECT

Qualche giorno fa, mentre scrivevo del codice server-side per un piccolo CRM homemade, ho avuto la necessità di ricavare dei dati mediante la UNION di due SELECT. In particolare, il codice SQL che ho utilizzato è il seguente:

SELECT 'Entrata' AS NomeTabella, O.ID, O.NumeroOperazione, E.Descrizione, E.Tipo, O.Importo, O.DataInserimento, O.DataOperazione FROM entrata AS E, riguarda AS R, operazione AS O WHERE O.ID = R.IDOperazione AND R.IDEntrata = E.ID AND (E.Tipo = 'Cassa' OR E.Tipo = 'Banca') UNION SELECT 'Uscita' AS NomeTabella, O.ID, O.NumeroOperazione, U.Descrizione, U.Tipo, O.Importo, O.DataInserimento, O.DataOperazione FROM uscita AS U, riguarda AS R, operazione AS O WHERE O.ID = R.IDOperazione AND R.IDUscita = U.ID AND (U.Tipo = 'Cassa' OR U.Tipo = 'Banca') ORDER BY DataInserimento
mysql.jpg

Ora, come potete notare le due SELECT vengono applicate su diversi JOIN ed hanno come obiettivo quello di restituire alcuni informazioni importanti, quali il numero dell’operazione finanziaria, la descrizione dell’operazione stessa, il suo importo, ecc. Ovviamente, affinchè i risultati non venissero ripetuti più volte ho utilizzato solo l’operatore UNION (che prevede un DISTINCT implicito) senza la direttiva ALL. Inoltre, per distinguere la tabella di provenienza dei record selezionati, ho creato un ulteriore campo temporaneo, a cui è stato associato l’alias NomeTabella. Così facendo, la struttura della tabella risultante è diventata la seguente:

Nometabella, ID, NumeroOperazione, Descrizione, Tipo, Importo, DataInserimento, DataOperazione

Da quel momento è stato possibile distinguere piuttosto banalmente la tabella di appartenenza dei record visualizzati.

Bye.

NB: affinchè la UNION possa essere applicata è necessario che le due SELECT riguardino lo stesso numero (e tipologie compatibili) di campi.