Denyhosts e IPtables

Tengo bastante tiempo usando Denyhosts para proteger el servidor de mi trabajo contra intentos de intrusión por fuerza bruta, especialmente por el puerto 22 (servicio de ssh).

Denyhosts funciona perfecto y hace lo que promete; cada que un “hacker” [mejor escrito: script kiddie]  intenta acceder por SSH con un nombre de usuario o una contraseña incorrecta más de 3 veces, Denyhost bloquea su IP agregando una entrada al archivo /etc/hosts.deny
De esa manera, el IP ofensivo ya no puede establecer conexión al servidor por el puerto 22

Editando la configuración del script intenté que Denyhost bloqueara todos los puertos para el atacante y que así no tuviera acceso al servidor; ¡pero no lo conseguí!

Después de muchas horas, al final, hice un pequeño script en bash que lee la lista de IPs en /etc/hosts.deny (agregadas previamente por DenyHost) para agregarlas  a iptables; logrando así, bloquear totalmente al ofensor.

Para ejecutar el script, solo hay que darle permisos de ejecución y opcionalmente, agregarlo al crontab
Espero que a alguien más le sirva este script para bloquear con iptables los IPs registrados por Denyhosts.

#!/bin/bash

# I will be kind to the computers in my network segment
MY_NETWORK_SEGMENT=148.228.204.

# File to store IP address
MY_HOSTS_DENY=/root/.hosts_deny

# Die if /etc/hosts.deny file not found
[ ! -f "/etc/hosts.deny" ] && { echo "File /etc/hosts.deny not found."; exit 1; }

# Filter the /etc/hosts.deny to generate MY_HOSTS_DENY file
grep -vE "^#|^S" /etc/hosts.deny | awk {'print $2'} | grep -v $MY_NETWORK_SEGMENT | sort -n > $MY_HOSTS_DENY

while read -r IP
do
 # check if the IP isn't blank
 if [ -n "$IP" ]
  then
   CURRENT_IP=$(iptables-save | grep $IP)
   # if the current IP does not exists in iptables rules then...
   if [ -z "$CURRENT_IP" ]
    then
     # Die IP, Die!
     iptables -A INPUT -p all -s $IP -j DROP
     echo "IP: $IP banned in ALL ports"
   fi
 fi
done <"${MY_HOSTS_DENY}"

# Clean the mess
rm $MY_HOSTS_DENY

Listas en cascada con jQuery, Kendo UI, XML y PHP

El problema es de lo más básico, sobre todo si se considera desde el punto de vista del usuario.

Desde el punto de vista del programador se trata de enlazar dos listas de selección, llenar las listas con los nodos de un archivo XML creado al vuelo a través de una consulta a una base de datos y filtrar la información dependiendo de la selección en la primera lista.
En forma visual se trata de lo siguiente.

Se tienen dos listas, la segunda lista está deshabilitada y se activa hasta que se haga una selección en la primera lista:

Con un XML (que se puede construir fácilmente con PHP) se llena la primera lista:

Cuando se elije una opción; se activa la segunda lista:

En la segunda lista, se filtran los datos del archivo XML para colocar únicamente los nodos que tengan correspondencia con la primera selección:

Ahora bien, para lograr esto, no se necesita reinventar la rueda pero si hay que poner algunas líneas de programación y comprender el proceso como se muestra a continuación:

Sigue leyendo

Cómo hacer el respaldo de moodle y todos los cursos

Empezaré por escribir que no soy un experto en moodle ni tampoco doy asesorías sobre su uso; lo cierto es que, como muchos; he tenido que ir aprendiendo paso a paso algunas cosas sobre la marcha, mientras se va utilizando esta magnífica plataforma educativa. Lo último con lo que me he tenido que enfrentar es con la realización de respaldos periódicos.

En este mini-micro tutorial, probablemente no logre escribir la octava maravilla, pero al menos espero que el compartir la forma en que yo he resuelto el asunto de los respaldos de moodle, le sirva a alguien más y lo ponga en práctica, o bien; que mejore la idea y la comparta con todos los lectores.

Considero que hay dos maneras de realizar respaldos, veamos la primera:

1.- Dentro de Moodle, en su interfaz gráfica se incluyen las herramientas para hacer respaldos de cada curso, de los alumnos inscritos, calificaciones, tareas, etc:

En el bloque administracion (dentro de tu curso) existe un botón llamado copia de seguridad que te permite crear un respaldo del curso con las opciones que tú elijas.

Este respaldo es un paquete zip que deberás restaurar cuando sea necesario, mediante la opción restaurar  en el bloque de administración del sitio.

El mayor dilema de este método es que se tiene que hacer, curso por curso y eso no es muy grato cuando tienes tantos cursos en la plataforma educativa o cuando quieres que cada determinado tiempo se hagan los respaldos de forma automática.

2.- La otra forma, es a través de un script que ejecuta algunas instrucciones directamente en el servidor; además este script se puede agregar al programador de tareas cron, para que se ejecute periodicamente.

Escencialmente lo que se tiene que respaldar es:

  • La base de datos de Moodle
  • La instalación de Moodle
  • Los archivos y recursos de todos los cursos, usuarios, etc.

He creado este script para hacer esas tres tareas consecutivamente; si te interesa usarlo, unicamente tienes que adaptarlo a tus variables de entorno:

#!/bin/bash
#Comprobamos que el usuario es root (super usuario) quien ejecuta este escript.
if [ $UID != 0 ]; then
 echo "No tienes los privilegios necesarios para ejecutar este script."
 echo "Debes ingresar como root, escribe \"su root\" sin las comillas."
 exit 1
fi

#Fecha actual
FECHA=$(date +%F);

#Hora actual
HORA=$(date +%H-%M-%S);

#Nombre del host en donde se ejecuta mysql (si hay dudas, ver moodle/config.php)
DBHOST=localhost

#Nombre de la base de datos  
DBNAME=moodledatabase

#Nombre del usuario que accede a la base de datos en mysql
DBUSER=moodleuser

#Clave de acceso a la base de datos en mysql
#Por defecto, se solicita cada vez que se ejecuta el script
#Pero se puede definir aqui
DBPASSWORD=""

#Directorio con la instalacion de moodle
MOODLE_DIR=/server/www/htdocs/moodle

#Directorio en donde se guardan los archivos de los cursos, las tareas, etc.
MOODLEDATA_DIR=/server/www/moodledata

#Directorio donde se guardaran los respaldos
BACKUP_DIR=/backups/moodle

#Respaldar la base de datos
if [ "$DBPASSWORD" = "" ]; then
 echo -n "Clave de acceso a la base de datos '$DBNAME' en mysql?: "
 read DBPASSWORD
fi
mysqldump -u $DBUSER -p$DBPASSWORD $DBNAME > $BACKUP_DIR/$DBNAME-$FECHA--$HORA.sql

#Comprimir el archivo de respaldo de la base de datos
echo "Desea comprimir el archivo de respaldo de la base de datos [Y/n]?"
echo -n " Valor por defecto [Y]: "
read COMPRESSDBFILE
if [ "$COMPRESSDBFILE" = "n" ]; then
 sleep 0
else
 bzip2 $BACKUP_DIR/$DBNAME-$FECHA--$HORA.sql
fi

#Hacer el archivo.tar.gz con el respaldo de moodle
tar czPf $BACKUP_DIR/moodle-$FECHA--$HORA.tar.gz $MOODLE_DIR

#Hacer el archivo.tar.gz con los archivos de los cursos, tareas, usuarios, etc
tar czPf $BACKUP_DIR/moodledata-$FECHA--$HORA.tar.gz $MOODLEDATA_DIR

##################################### FIN DEL SCRIPT ##################################

Puedes copiar y pegar el código de arriba y guardarlo en un archivo con extensión .sh o bien, bajar el script de este enlace; después sólo tienes que subirlo a tu servidor, editar las variables como son, el nombre de la base de datos, el nombre del usuario, la ubicacion a los directorios de moodle y el directorio donde se guarda el respaldo; para ejecutar el script tienes que cambiarle los permisos de ejecución; desde tu terminal escribe:

chmod +x backupMoodle.sh

y para ejecutarlo:

./backupMoodle.sh

Finalmente, espero que esa publicación sea de ayuda para más personas.

Script para la gestión de usuarios en bash

#!/bin/bash
#Comprobamos que el usuario es root.
if [ $UID != 0 ]; then
 echo "No tienes los privilegios necesarios para ejecutar este script."
 echo "Debes ingresar como root, escribe \"su root\" sin las comillas."
 exit 1
fi

echo
echo "Administración básica de usuarios y grupos en linux"
echo

while [ "$option" != "0" ]
 do
 clear
  echo
  echo "Opciones:"
  echo "---------"
  echo " 1. Agregar un usuario al sistema."
  echo " 2. Cambiar la clave de acceso de un usuario."
  echo " 3. Editar la información personal de un usuario."
  echo " 4. Borrar a un usuario del sistema."
  echo " 5. Crear grupo."
  echo " 6. Agregar un usuario a un grupo."
  echo " 7. Borrar un grupo."
  echo " 0. Salir."
  echo
  echo -n " Ejecutar: "
   read option
   case $option in
    1 )
     echo
     echo -n "Nombre del usuario a crear?: "
     read username
     echo "Con acceso a la línea de comandos bash [Y/n]?"
     echo -n " Valor por defecto [n]: "
     read shell_access
     if [ "$shell_access" = "Y" ]; then
       TERMINAL='/bin/bash'
     else
      TERMINAL='/bin/false'
     fi
     echo "Crear el directorio de trabajo para el nuevo usuario [Y/n]?"
     echo -n " Valor por defecto [Y]: "
     read home_directory
     if [ "$home_directory" = "n" ]; then
      useradd $username -s $TERMINAL
     else
      useradd $username -m -s $TERMINAL
     fi
     echo
    ;;
    2 )
     echo
     echo -n "Nombre del usuario del que se desea cambiar la clave?: "
     read username
     echo
     passwd $username
     echo
    ;;
    3 )
     echo
     echo -n "Nombre del usuario al cual cambiar la información personal?: "
     read username
     echo
     chfn $username
     echo
    ;;
    4 )
     echo
     echo -n "Nombre del usuario a borrar?: "
     read username
     if [ "$username" = "root" ]; then
      echo "Estúpido script, no puedes eliminar al Dios root"
      exit 0
     else
      echo
      echo "Desea borrar el directorio de trabajo y todo su contenido [Y/n]? "
      echo -n " Valor por defecto [n]: "
      read delete_home
     fi
     if [ "$delete_home" = "Y" ]; then
      userdel -r $username
     else
      userdel $username
     fi
     echo
    ;;
    5 )
     echo
     echo -n "Nombre del grupo a crear?: "
     read group
     echo
     groupadd $group
     echo    
    ;;
    6 )
     echo
     echo -n "Nombre del usuario para agregar al grupo?: "
     read username
     echo -n "Nombre del del grupo para agregar el usuario?: "
     read group
     echo
     groupadd $username $group
     echo
    ;;
    7 )
     echo -n "Nombre del grupo a borrar?: "
     read group
     echo
     groupdel $group
     echo
    ;;
    *) 
    ;;
   esac
  done
echo
exit 0

Evitar la sobre escritura de archivos cargados con php

Pues aquí dejo un segmento de código que me parece algo sencillo pero puede ser útil a otros (además de que no compromete la confidencialidad de mis proyectos laborales) y sirve únicamente para renombrar un archivo que se sube por formulario web para evitar la sobrescritura; eso se hace agregando una serie numérica entre el nombre del archivo y su extensión:

<?php
/**
* @author Javier B. Camacho Martínez
* @copyright DGB - Agosto 2009
*/

$fileSize = $_FILES['fileUploaded']['size'];
$fileName= $_FILES['fileUploaded']['name'];
$fileType = $_FILES['fileUploaded']['type'];
$fileTmp
= $_FILES['fileUploaded']['tmp_name'];

// Reemplazar espacios y signos de puntación del nombre de archivo por guiones bajos
$fileName
= preg_replace('/[^a-z0-9-_\-\.]/i','_',$fileName);

// Obtener la extensión del archivo (a veces resulta útil saberlo)
$extFile
= substr($fileName,-4,4); // mantiene desde -4 a 4 caracteres: .txt

// Obtener el puro nombre del archivo (sin la extensión)
$fileName
= substr($fileName,0,-4); // mantiene desde 0 hasta -4 caracteres: carta_a_los_reyes_magos
$uploadsFolder
= './uploads/';

// Si no existe el directorio para almacenar los archivos, crearlo con permisos 777
!
is_dir($uploadsFolder) ? mkdir($uploadsFolder,0777) : null;

// Antes de mover el archivo al directorio, prevenir la sobre escritura
if(
file_exists($uploadsFolder.$fileName.$extFile)){
$counter = 1;
while(@
file_exists($uploadsFolder.$fileName.'_'.$counter.$extFile)) { $counter++;  }
// Si existe se renombra a con un infijo numérico: carta_a_los_reyes_magos_2.txt
$fileName = $fileName.'_'.$counter.$extFile;
}
// Si no existe, no se renombra y queda tal cual: carta_a_los_reyes_magos.txt

else{

$fileName
= $fileName.$extFile;
}

// Mover el archivo a su nuevo hogar:
$statusMovedFile
= move_uploaded_file($fileTmp,$uploadsFolder.$fileName);

// Verificación final
echo
'el status es: '.$statusMovedFile;
?>

A dormir buho

Estos últimos días he dormido poco, pero hoy fue mi último día de desvelo, al menos en esta semana.

Son las 03:47 am del día Sábado y al fin, he terminado la galería de las pulseras de plata que estamos armando (Landy y yo); así que ya me puedo irme a dormir unas buenas 8 horas seguidas.

Espero que todo el esfuerzo invertido, nos de buenos dividendos.

See ya.

Detección de fuentes no citadas

Hasta hace algunos meses, yo no consideraba importante realizar citas bibliográficas en mis trabajos escolares ni mucho menos hacer referencias a las fuentes de información que había consultado.

De hecho, de no ser por… una gran persona, no hubiera adquirido el buen hábito de agregar las referencias necesarias cuando incluyo un texto en una presentación, cómo la que hice algunas semanas para la materia de Problemas actuales de México, y aunque mi estilo realmente necesita una refinación, creo que ya voy al menos por el buen camino de incluir las citas, lo cierto es que intento adoptar el estilo APA así que tendré que documentarme bien para lograr el objetivo.

A raíz de estas buenas costumbres adquiridas por influencia regia, he propuesto el nuevo proyecto que desarrollaré para la DGB y que consiste en lo siguiente:

  • Tomar un archivo de texto, de inicio sólo pdf’s o txt
  • Extraer su contenido
  • Segmentar el documento en fragmentos semánticos de 25 palabras o bien, por oraciones completas (hasta donde aparezca un punto y seguido o un punto final)
  • Buscar el fragmento en Internet usando la API AJAX de Google para búsquedas
  • Si el fragmento está registrado en Internet, quiere decir dos cosas:
    1) El fragmento incluido no es propiedad intelectual del autor
    2) Se ha omitido hacer la cita o referencia pertinente lo cual puede ser penalizado por cuestiones de autoría.
  • Al final del análisis el sistema dirá qué porcentaje de originalidad tiene el documento, en base al número de fragmentos que lo componen y el número de coincidencias localizadas en la web.

En sí, eso fue lo que presenté en la reunión que tuvimos el viernes en la Unidad de Recursos Interactivos como parte de la revisión por la dirección que se efectúa el último viernes de cada mes.

Honestamente, me sentí muy nervioso durante la presentación, especialmente porque estaba mi jefe, los directores de todas las bibliotecas, coordinadores de otras áreas como Sistemas, Diseño gráfico, Bibliometría, etc…. puuffff y a mi que me gusta tener el mayor control posible; la verdad es que no logré mantener el pulso normal.

Al final, mi jefe quedó complacido con la idea del proyecto y también hubo buenas sugerencias aunque no faltó el que me preguntó porqué iba yo a utilizar el API de Google y no a realizar un desarrollo desde cero como siempre lo he realizado.

De entrada, estoy convencido que no voy a re inventar la rueda y este proyecto supone varios retos interesantes pese a lo que pudieran pensar algunas personas; como sea, creo que este proyecto puede ser útil incluso para más personas de las que comprende la DGB; lo cual me pone contento porque de esa manera, se puede impactar en otras áreas de oportunidad y mostrar lo que se está haciendo al interior de las bibliotecas que es más que prestar libros y hacer encuentros bibliotecarios un par de veces al año…

Al final, solo resta una línea:

Gracias por la inspiración.