El tinglado que me he montado está basado en un artículo de linux.com, aunque usando herramientas diferentes (salvo el syslogd). Consta de varias partes:
- Modificación de syslog.conf para enviar algunos mensajes a un fichero fifo.
- Creación de un script en perl para filtrar los mensajes deseados.
- Envío de dichos mensajes mediante una versión modificada de sJab.
- Creación de un servicio monitorizable por daemontools.
Vayamos pues, por partes (me ahorro el chiste de Jack el Destripador).
1. Modificación de syslog.conf
Primero debemos crear (como root) el directorio y el fichero fifo:
mkdir /etc/syslog-jabber
chmod o-rx /etc/syslog-jabber
mkfifo /etc/syslog-jabber/fifo
Edítese syslog.conf y añádase lo siguiente:
auth,authpriv.* |/etc/syslog-jabber/fifo
En mi caso sólo he puesto los eventos auth porque son los que me interesan, pero lógicamente se pueden poner otros cualesquiera. (Nota aparte: algún día entenderé por qué en Libertonia algunos bloques entre <code> y </code> salen con tipo de letra a tamaño fijo y otros no). Después hay que hacer que syslogd lea la nueva configuración, con /etc/init.d/sysklogd reload si se trata de un sistema tipo System-V, o buscando su pid y enviándole un HUP (kill -HUP nº_de_pid)
2. Parser en perl
Se trata simplemente de filtrar los mensajes que nos interesen, en mi caso cuando alguien entra al sistema desde fuera y cuando alguien no introduce la contraseña correcta para su. La adaptación a otros mensajes es trivial, basta ver cómo son examinando los diferentes ficheros de /var/log. Al filtro en cuestión lo llamamos parseauth.pl y lo grabamos en el directorio que vamos a usar para todo este cirio (/etc/syslog-jabber).
#!/usr/bin/perl
#
use strict;
my $tema;
my $msj;
open (FIFO, "</etc/syslog-jabber/fifo") || die ("No se pudo abrir el fifo\n");
while (<FIFO>) {
if (m/^\w\w\w\s+\d+ \d\d:\d\d:\d\d \w+ PAM_unix\[\d+\]: authentication failure; (\w+)\(uid=\d+\) -> \w+ for su service$/) {
$tema="Fallo en su: $1";
$msj=$_;
system("echo '$msj' | /etc/syslog-jabber/sJab -u remitente -p contraseña -t destinatario -q '$tema'");
}
if (m/^\w\w\w\s+\d+ \d\d:\d\d:\d\d \w+ sshd\[\d+\]: Accepted password for (\w+) from (\S+) port \d+ ssh2$/) {
if ($2 ne "miip") {
$tema="Intruder Alert";
$msj="$1 ha entrado desde $2";
system("echo '$msj' | /etc/syslog-jabber/sJab -u remitente -p contraseña -t destinatario -q '$tema'");
}
}
}
Hay varias cosas a modificar aquí:
- remitente: El usuario jabber que se usará para enviar los mensajes. Tiene que estar registrado previamente en el servido jabber que se utilice.
- destinatario: El BOFH que tiene abierto su cliente jabber y recibe los avisos.
- contraseña: La de remitente en el servidor jabber.
- miip: En mi caso no quiero que me avisen cuando yo mismo entro, así que he puesto ese if; cada cual que lo adapte a sus necesidades.
Nota sobre seguridad: si no usáis grsecurity o algo similar, contraseña será visible por cualquier usuario que pueda hacer un ps. Un posible apaño es ponerlo directamente en el scritp sJab.
3. Versión modificada de sJab
La principal modificación sobre la versión oficial es que admite el tema del mensaje como parámetro. Posiblemente tenga otras, ya no lo recuerdo. En todo caso pego aquí el tocho y así cumplo con la GPL :)
#!/usr/bin/perl
# sJab - An simple Jabber command-line client written in Perl.
#
#####################################################################
# #
# Please note that this release is incredibly alpha. In fact, so #
# alpha, it probably shouldn't even be released. #
# #
#####################################################################
#
# Version : 0.01a
#
# Author : Kris Merrill (kmerr001@cs.fiu.edu)
# Credits : Ryan Eatmon (Jarl)
# DJ Adams (sJabber)
#
# Usage : To send a message to a user..
# sJab -u <user> -p <password> -m <message>
#
# To send a piped stream to a user...
# <program> | sJab -u <user> -p <password>
#
# To send a message to a group chat (conference) ...
# sJab -u <user> -p <password> -c <room> -s <server> -m <message>
#
# To send a piped stream to a group chat...
# <program> | sJab -u <user> -p <password> -c <room> -s <server>
#
#####################################################################
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
#
# Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
#
#####################################################################
use Net::Jabber qw(Client);
use Getopt::Std;
#use strict;
getopt('upcstmq',\%opts); # Get options
if ($opts{c} && $opts{t}) {
print "Please specify either a user or conference room. Not both.\n";
exit(0);
}
if ((!$opts{u} || !$opts{p}) && (!$opts{c} || !$opts{t})) {
print
"sJab v0.01a
sJab [-u <user> -p <password>]
[-c <conference> -s <server>] [-t <recipient>]
[-m <message>]
-u User sJab will login as.
-p Password for sJab user.
-c Conference room.
-s Conference server.
-t User to send message.
-m Message, if not using standard input.
-q tema
-h Displays this screen.
Example Usage
To send a message to a user:
sJab -u user -p password -t JabberUser -m Hello.
To send a message to a conference:
sJab -u user -p password -c scs -s conference.scs -m Alert.
";
exit;
}
# Jabber-Specific "Constants"
#my $SUBJECT = "Aviso sJab";
my $SUBJECT = $opts{q};
my $SERVER = "servidor_jabber";
my $PORT = 5222; # Jabber Port
my $SJABUSER = $opts{u}; # Jabber User
my $SJABPASSWD = $opts{p}; # Jabber Password
my $RESOURCE = "sJab"; # Jabber Presence
my $PRESENCE = "on"; # Jabber Presence
my $PRIORITY = 0;
# User Defined Variables
my $conference = $opts{c}; # Conference Room
my $server = $opts{s}; # Jabber Server
my $user = $opts{t}.'@'.$SERVER;
my $msg = $opts{m};
# Connect to Jabber Server
$jabber = jabberConnect(
$SERVER,
$PORT,
$SJABUSER,
$SJABPASSWD,
$RESOURCE,
$PRESENCE);
# If a Message is defined, don't use STDIN
if ($opts{t} && $opts{m}) {
jabberMessage($user, $SUBJECT, $msg);
}
elsif ($opts{c} && $opts{s} && $opts{m}) {
jabberGroup($conference,$server,$msg);
}
else {
# Take input from STDIN
while ($_ = <>) {
#chomp $_;
# If $user is defined, send to user
if ($opts{t}) {
$msg.=$_;
#jabberMessage($user, $SUBJECT, $_);
}
# Otherwise send to Group Chat Room
elsif ($opts{c} && $opts{s}) {
jabberGroup($conference,$server,$_);
}
# If all else fails, quit.
else {
exit(0);
}
}
jabberMessage($user, $SUBJECT, $msg) if ($opts{t});
}
# Disconnect from Jabber Service
$jabber->Disconnect();
exit;
#################################################
# Subroutines
#################################################
sub jabberConnect {
# desc | Connects user to Jabber Service.
# accepts | server, port, sjabuser, sjabpasswd, resource, presence
# returns | Net::Jabber connection client
my ($server, $port, $sjabuser, $sjabpasswd, $resource, $presence) = @_;
my $connection = new Net::Jabber::Client;
# Connect
die "Cannot connect to Jabber server: $server:$port\n"
unless (defined $connection->Connect(
hostname => $server,
port => $port,
));
print "Connected to Jabber server: $server:$port\n";
# Identify / Authenticate Oneself to the Server
my @result = $connection->AuthSend(
username => $sjabuser,
password => $sjabpasswd,
resource => $resource
);
die "Authentication failed: $result[0] - $result[1].\n"
if $result[0] ne "ok";
print "Authentication as $sjabuser was sucessful.\n";
return $connection;
}
# Message Subroutines
#################################################
sub jabberMessage {
# desc | Sends Message to User
# accepts | user subject body
# returns | nothing
my ($user, $subject, $body) = @_;
# Create Message Object
my $message = new Net::Jabber::Message;
$message->SetMessage(
To => $user,
Subject => $subject,
Body => $body,
);
# Send Message
$jabber->Send($message);
}
# Group Subroutines
#################################################
sub jabberGroupJoin {
# desc | Join a Jabber Group
# accepts | gname gserver
# returns | nothing
my ($gname, $gserver) = @_;
# Join Group / Send User Presence
my $presence = new Net::Jabber::Presence;
$presence->SetTo($gname.'@'.$gserver.'/'.$SJABUSER);
# Send
$jabber->Send($presence);
}
sub jabberGroupMsg {
# desc | Write Message to Group
# accepts | gname gserver body
# returns | nothing
my ($gname, $gserver, $body) = @_;
# Create Message
my $groupmessage = new Net::Jabber::Message;
$groupmessage->SetMessage(
To => $gname.'@'.$gserver,
Body => $body,
);
# Send
$jabber->Send($groupmessage);
}
sub jabberGroupLeave {
# desc | Leave a Jabber Group
# accepts | nothing
# returns | nothing
# Join Group / Send User Presence
my $presence = new Net::Jabber::Presence;
$presence->SetPresence(
Type => 'unavailable',
To => $gname.'@'.$gserver,
);
}
sub jabberGroup {
# desc | Joins a Group and Sends Message
# accepts | gname gserver body
# returns | nothing
my ($gname, $gserver, $body) = @_;
jabberGroupJoin($gname, $gserver); # Join Group
jabberGroupMsg($gname, $gserver, $body); # Send Message
jabberGroupLeave($gname, $gserver); # Leave
}
Aquí deberemos cambiar servidor_jabber por el servidor en el que estén registrados nuestros amigos destinatario y remitente. Grábese en el directorio /etc/syslog-jabber.
4. Creación del servicio
Tal como está ya funcionaría el sistema (ejecutando parseauth.pl), pero si tenemos daemontools podemos utilizarlas para que lo vigilen como un servicio más. Creamos /etc/syslog-jabber/run con el siguiente contenido:
#!/bin/sh
echo Iniciando syslog-jabber
# direct std err to std out, for log
exec 2>&1
exec /usr/bin/perl /etc/syslog-jabber/parseauth.pl
Damos permiso de ejecución y creamos el directorio para el log:
chmod 700 /etc/syslog-jabber/run
mkdir /etc/syslog-jabber/log
Creamos /etc/syslog-jabber/log/run con el siguiente contenido:
#!/bin/sh
# with tai64n time format and 3 logfiles of size 50000 kB
multilog t s50000 n3 ./main
Y le damos permiso de ejecución (chmod 700 /etc/syslog-jabber/log/run). Ya sólo queda dar de alta el servicio: ln -s /etc/syslog-jabber /service/syslog-jabber, que por obra y gracia de daemontools empezará a funcionar. Como en cualquier otro servicio de estos, lo podemos parar con svc -d syslog-jabber y volver a levantar con svc -u syslog-jabber.