cURL: El arte del HTTP scripting. Un caso práctico

cURL: El arte del HTTP scripting. Un caso práctico

"Webmin: Export users to batch file"

Juan Felipe Muñoz - Fernández

 

::[INTRO]::

Una de las cosas más comunes que como Sysadmin se hacen, es la de automatizar alguna tarea administrativa. Por ejemplo, automatizar un backup de ciertos archivos todos los días a las 18:00 horas, automatizar una descarga de un archivo de Internet cada semana a las 13:00 horas, automatizar la impresión de ciertos documentos cada semana a la 01:00 horas, etc.

Aquí traigo un caso practico para automatizar tareas que requieren el uso del protocolo HTTP (por ejemplo cuando necesitamos descargar cada semana un archivo de Internet).

Como indica el titulo, la herramienta a utilizar se denomina cURL:

"cURL es una herramienta en línea de comandos para la transferencia de archivos con sintaxis de URL, soportando FTP, FTPS, TFTP, HTTP, HTTPS, TELNET, DICT, FILE y LDAP. cURL soporta certificados SSL, HTTP POST, HTTP PUT, FTP uploading, HTTP form based upload, proxies, cookies, autenticación basada en usuario+password (Basic, Digest, NTLM, Negotiate, Kerberos, etc.), descargas de archivos resumidas, proxy tunneling y otros útiles complementos."

El sitio oficial de cURL es http://curl.haxx.se/. Para que cURL soporte SSL se requiere previamente las librerías del proyecto OpenSSL. Consulte la documentación para compilar cURL y habilitar el soporte de SSL. cURL está disponible para varios sistemas operativos incluyendo Linux y Windows.

 

 

::[PROBLEMA]::

Se requiere hacer una copia semanal de seguridad de las cuentas de usuario de un sistema Linux en el formato que entrega Webmin haciendo uso de la utilidad "Export users to batch file" (Webmin - System - Users and Groups - Export users to batch file)

 

 

::[DISCUSIÓN]::

Webmin es una herramienta Web para la administración de sistemas Unix - Like. Webmin posee una utilidad (via Web) con la que se puede exportar toda la información de las cuentas de usuario a un archivo de texto de tal manera que si hay que llevar a cabo un procedimiento de recuperación del sistema, no sea necesario crear una a una y "a mano" todas las cuentas de usuario que previamente habíamos creado. Como es de esperarse, Webmin dispone de la utilidad para hacer la importación de cuentas de usuario tomando el archivo creado con la utilidad de exportación.

Un mortal (como yo) comodamente podría entrar cada semana a Webmin, hacer clic en el módulo "System", luego hacer clic en el módulo "Users and Groups", para luego ir tras el link que dice "Export users to batch file", llenar los campos que el formulario requiere y finalmente hacer clic en "Export Now". ¡Pero no! yo quiero ser más cómodo aún, me creo un shell script (estoy hablando de Linux, veremos el homólogo para Windows) que utilice cURL para rellenar ese formulario (el de "Export users to batch file") y sacar mi archivo de usuarios cada semana de manera automática (después me "descalabro" pensando como hago para que mi shell script se ejecute cada semana).

¡Ah! ¡Pero hay un problema!, para llegar hasta el formulario "Export users to batch file" necesito autenticarme primero ante Webmin. Igual, si cURL puede rellenar el formulario "Export users to batch file", también puede meter los datos de "Username" y "Password" en el formulario a la entrada de Webmin.

Supongo que ustedes conocen Webmin :)

 

 

::[FASE 1 - AUTENTICACION]::

En esta fase me concentraré en como hacer para que cURL pueda "meter" los datos en el formulario de entrada a Webmin.

Para los que no conocen Webmin, cuando nos conectamos al puerto que éste escucha (TCP/10000) a través de HTTP, de la forma http://127.0.0.1:10000, Webmin nos pinta en la ventana del Browser de nuestra preferencia (el mio es Firefox) una página que tiene un campo "Username", otro campo "Password" y dos botones "Login" y "Clear" respectivamente.

En este punto nos asalta una primera duda: como sabemos, el formulario de Login envía el nombre de usuario y la contraseña entrados en los campos "Username" y "Password" respectivamente con el método POST del protocolo HTTP. Este método normalmente es utilizado para enviar los datos de un formulario de una página Web de manera "oculta" (van a ver porque lo pongo entre comillas), más bien, de manera que no lo vea el usuario.

Para ser simples y claros HTTP maneja dos métodos para la transmisión de cierta información a través de formularios Web: GET y POST, GET es un método que envía todos los datos de un formulario en el mismo URL, por ejemplo: http://www.loquesea.com/procesarinfo.cgi?usuario=pepito&password=123 (y digan que no han visto eso algunas veces navegando por ahí). En este ejemplo usuario=pepito&password=123 son los nombres de los campos y sus valores asignados en un formulario. Normalmente cuando se rellena un formulario con información, ésta (la información) se le entrega a un programa (.php, .cgi, .asp, etc.) que procesa los valores entregados (para validar un usuario y una contraseña por ejemplo). En el ejemplo anterior, el programa procesarinfo.cgi es el encargado de procesar la información recibida como parámetro en el URL después del símbolo "?". Con el método GET, cada campo del formulario va explícito en el URL (al que apunta el formulario) en la forma campo = valor, separando cada par con el símbolo "&" .

El método POST envía exactamente lo mismo pero no en el URL, sino como parte del contenido HTTP que se está enviando, ya veremos.

El punto aquí es que como es de esperarse, Webmin utiliza el método POST en el formulario de autenticación. Entonces tendríamos que saber como es que viajan los campos del formulario de autenticación de Webmin con el método POST. Para ello tenemos dos soluciones posibles:

1. Utilizar un Proxy local como Achilles para capturar el tráfico HTTP entre el Browser y Webmin.

2. Guardar una copia local de la página de Login en el PC, luego editarla y cambiar el método POST del formulario por el método GET, de tal manera que abriendo esta copia local en el Browser, llenando los campos del dormulario y haciendo clic sobre el botón "Login", veríamos en el URL todo los valores que hay que pasar y a dónde hay que pasarlos.

En este documento me voy a centrar en el primer método.

 

 

ACHILLES Y EL BROWSER

Achilles es un Proxy local. ¿Como así? Un proxy como Achilles es un pedazo de software que se interpone entre el Browser de Intenet y el Servidor Web hacia el cual estamos enviando peticiones HTTP y recibiendo contenido. Achilles entra en el medio de los dos capturando cada petición enviada por nuestro Browser y capturando cada respuesta enviada por el Servidor Web.

La instalación de Achilles no la voy a discutir. Basta con hacer doble clic en el ejecutable, marcamos las opciones "Intercept Mode On" e "Intercept Client Data".

Luego abrimos nuestro Browser de Internet preferido y hacemos la petición hacia la máquina en donde tenemos Webmin instalado, por ejemplo: http://10.100.0.253:10000, llenamos los campos del formulario de Login de Webmin:

 

Username: root
Password: ********

 

y antes de hacer clic sobre el botón "Login", hacer esto:

Si el browser es Internet Explorer: Clic en "Herramientas", clic en "Opciones de Internet", clic en el tab "Conexiones", clic en el botón "Configuración de LAN", marcar la opción "Utilizar un servidor proxy para su LAN. Esta configuración...", sobre el campo dirección entrar el valor 127.0.0.1 y en el campo "Puerto" entrar el valor 5000, finalmente hacer clic en "Aceptar".

Si el browser es Mozilla Firefox: clic en "Herramientas", clic en "Opciones", sobre los iconos del lado izquierdo, hacer clic en "General", luego sobre el panel derecho hacer clic sobre el botón "Configuración de conexión...", seleccionar la opción "Configuración manual de proxy", marcar la opción "Usar el mismo proxy para todos los protocolos", en el campo "Proxy HTTP" agregar el valor 127.0.0.1, en el campo "Puerto" agregar el valor 5000, finalmente clic en "Aceptar".

Luego de configurar el Browser para que utilice como proxy Achilles, nos devolvemos a la ventana de Achilles y en la barra de herramientas le damos clic al botón "Start Proxy".

¡Ahora si! Sobre el formulario de Login de Webmin, hacemos clic sobre el botón Login y veremos algo similar a lo mostrado en la siguiente imagen:

Click sobre la imagen para ver tamaño real.

 

Como se alcanza a ver en la imagen, el primer recuadro rojo corresponde al recurso en donde los parámetros "Username" y "Password" son evaluados: session_login.cgi y el segundo recuadro son los valores del formulario que se pasan al programa session_login.cgi para su validación. Podemos concluir entonces que el formulario de incio de sesión de Webmin envía al programa sesion_login.cgi los siguientes valores:

 

page=%2F
user=<nombre de usuario, normalmente root>
pass=<password del usuario>

 

Obviamente, el envio de estos datos con el método POST se hace de la siguiente manera:

page=%2F&user=<nombre de usuario, normalmente root>&pass=<password del usuario> 

Hasta este punto tenemos lo necesario para comenzar la primera parte del HTTP scripting con cURL.

 

PRIMER INTENTO CON cURL

Vamos entonces a poner en tela de juicio lo concluido.

Nos abrimos un terminal o una consola de DOS para los que trabajan con Windows y en el Prompt vamos a colocar lo siguiente (no sobra decir que la máquina en donde tengo instalado el Webmin es la 10.100.0.253, ustedes debrán cambiar este valor por el de sus necesidades):

 

curl -d "page=%2F&user=root&pass=mipassword" http://10.100.0.253:10000/session_login.cgi

 

Note como he incluido el recurso session_login.cgi en la petición. Recordemos que los datos del formulario de inicio de sesión de Webmin son enviados a este recurso para su validación.

La opción "-d" le indica a cURL que los datos pasados a continuación deben enviarse con el método POST. Aquí recomiendo una leídita de la documentación de cURL.

¿El resultado de lo anterior? ¡Mala cosa! esto es lo que obtuvimos:

 

<h1>Error - No cookies</h1>
<pre>Your browser does not support cookies, which are required for this web server to work in session authentication mode</pre>

 

En otras palabras: hemos fallado. El servidor Web de Webmin nos responde diciéndonos que nuestro Browser no soporta Cookies. Mala cosa, por lo que intuimos que una vez autenticados, Webmin nos entrega una Cookie con la información de sesión. Sigamos en la lectura y observemos que sucede.

 

SOBRE LAS COOKIES

Para no botar corriente explicando que es una cookie, aquí les dejo el enlace: http://es.wikipedia.org/wiki/Cookie

Lo que tenemos que saber es como diablos se crean las Cookies, ya que en el primer intento al parecer no se pudo crear la Cookie asociada a la sesión de autenticación ya que nuestro Browser (en este caso cURL) no soporta Cookies. Veamos:

Una Cookie se crea en tres pasos:

Una pregunta común que se hacen los desarrolladores Web es: ¿como se sabe si un browser acepta o no Cookies? La única manera de saber si un browser acepta Cookies o no es que el browser envie el tercer encabezado, es decir, añadiendo al encabezado HTTP el header "Cookie:". Obviamente el tercer encabezado no puede ser enviado por el cliente, si antes el servidor no envio el encabezado numero dos. De esta manera, el servidor Web sabe si el cleinte acepta Cookies o no.

 

SEGUNDO INTENTO CON cURL

Con la "carreta" anterior ya podemos intentar algo. Pero antes, observemos la imagen con Achilles nuevamente y veremos que en la petición está viajando el encabezado "Cookie:"

 

Cookie: testing=1

 

¡Oh! Que curioso

Vemos que Webmin para validar si nuestro Browser soporta Cookies, debió enviar el encabezado número dos, con algo como lo siguiente:

 

Set-Cookie: testing=1

 

Hagan el ejercicio con Achilles marcando la opción "Intercept Server Data" para corroborar lo anterior.

Ahora bien ¿y como mandamos el encabezado "Cookie: testing=1" (recordemos que este encabezado lo manda el cliente)? Fácil, con la opción "-H" de cURL que permite enviar encabezados adicionales en la petición. Pero antes de ello, debemos almacenar la Cookie devuelta por Webmin en alguna parte, para esto nos sirve la opción "-c <archivo en donde almacenar la cookie>" de cURL. Veamos:

 

curl -d "page=%2F&user=root&pass=mipassword" -H "Cookie: testing=1" -c cookies.txt http://10.100.0253:10000/sesion_login.cgi 

 

¿Que pasó? No veo ningún mensaje de error, miremos entonces a ver si en el directrorio actual de trabajo hay un archivo llamado cookies.txt. ¡Oh! claro que está, miremos dentro de este archivo para ver que hay allí:

 

# Netscape HTTP Cookie File
# http://www.netscape.com/newsref/std/cookie_spec.html
# This file was generated by libcurl! Edit at your own risk.

10.100.0.253    FALSE   /       FALSE   0       sid     45cd296ea05e46037ac5470d8539f226

 

Parece que todo va bien. Vemos que hay un identificador de sesión válido. Hemos logrado nuestro primer objetivo. Ahora si estamos autenticados ante Webmin.

 

 

::[FASE 2 - EXPORT USERS TO BATCH FILE]::

Creo que la fase anterior nos ha dejado algo cansados, pero con seguridad, toda la "retaila" de aspectos ténicos del protocolo HTTP y demás era necesaria para resolver el problema.

Ahora lo que sigue es usar la COOKIE DE SESIÓN obtenida en la FASE 1 para llegar hasta el formulario "Export users to batch file", llenar lo datos y finalmente obtener nuestro preciado archivo de toda la configuración de cuentas de usuario del sistema.

Recordemos que el propósito de una COOKIE (entre otras cosas) es mantener una asociación del agunos datos de nuestra sesión en una aplicación (por ejemplo nuestra información de autenticación en Webmin). Esto es porque HTTP es un protocolo de la capa de aplicación el cual no es orientado a la conexión, aspecto en el cual no pienso profundizar ahora. Lo único que debe quedar claro en este punto es que de aquí en adelante tendremos que usar la COOKIE de la FASE 1 (cookies.txt) para hacer la petición a la utilidad de Webmin "Export users to batch file".

Para hacer que cURL utilice una COOKIE ya almacenada (en alguna parte, en nuestro caso la cookie obtenida está en el archivo cookies.txt) se debe pasar la opción "-b <cookie>" siendo <cookie> un archivo con la información de la cookie o bien los valores propiamente dichos de la cookie en el formato "NOMBRE1=VALOR1; NOMBRE2;VALOR2". Un dato importante: si <cookie> es un archivo, éste tiene que ser en el formato de archivo de cookie que manejan los Browsers Netscape/Mozilla.

Ahora vámonos para Webmin, nos metemos por la categoría "System", luego por "Users and Groups", finalmente "Export users to batch file". El único cambio que voy hacer en el formulario es el siguiente:

Selecciono la opción "Write to file" y le asigno el valor /home/juanmuno/usuarios

De esta manera le digo a la utilidad "Export users to batch file" que me exporte toda la infiormación de las cuentas de usuario a un archivo local llamado "usuarios" en la ubicación "/home/juanmuno". Luego pulso en el botón "Export Now" y ¡ mire lo que hay en el URL!:

 

http://10.100.0.253:10000/useradmin/export_exec.cgi?to=1&file=%2Fhome%2Fjuanmuno%2Fusuarios&pft=2&mode=0&can=&cannot=&uid=&uid2=&group=&gid=&gid2=

 

La primera conclusión que usted se debe estar haciendo ya, es la siguiente: el formulario de la utilidad "Export users to batch file" es un fornmulario que envía los datos con el método GET a un programa llamado export_exec.cgi. ¿Si o no?

Bueno, ahora descompongamos parte de este conjunto de parámetros que vienen después del símbolo "?". (Recuerden que cada par CAMPO=VALOR está separado por el símbolo "&".

to=1. Corresponde al valor de las opciones: "Display en browser" ó "Write to file". Siendo igual a 0 cuando se selecciona la primera opción y 1 cuando seleccionamos la segunda opción (como se acaba de hacer en este ejemplo).

file=%2Fhome%2Fjuanmuno%2Fusuarios. Indica en que ruta local y con que nombre debe quedar el archivo que almacanerá la información de las cuentas de usuario. Ya vi la pregunta: ¿y que diablos hacen esos %2F ahí?. Bueno, para no alargar mucho el cuento. En HTTP existen algunos caractéres especiales como el slash ("/"). Estos caractéres deben ir codificados en código hexadecimal, precedidos del signo "%". Así, 2F corresponde en decimal a 47 y 47 es el código ASCII del caractér "/".

pft=1. Corresponde a la opción "Batch file format". Bueno, ya mencioné que Webmin sirve para administrar sistemas Unix-Like, de ahí esta opción.

Bueno....creo que es suficiente ilustración estos tres parámetros. Si usted desea hacer cosas más especiales con la utilidad "Export users to batch file" y cURL le dejo a su inquisitiva mente como hacerlo. Yo seguiré el resto de este artículo con el URL generado a partir de la información suministrada al formulario:

Ya tenemos entonces lo necesario para hacer la petición completa a Webmin con cURL. ¡Entonces hagámoslo!

 

curl -b cookies.txt "http://10.100.0.253:10000/useradmin/export_exec.cgi?to=1&file=%2Fhome%2Fjuanmuno%2Fusuarios&pft=2&mode=0&can=&cannot=&uid=&uid2=&group=&gid=&gid2=" -o salida.html

 

Yo recomiendo que todo el URL se encierre entre comillas dobles para evitar algunos problemas comunes. La opción "-o" hacer que la salida generada por el comando cURL, que si todo funciona bien debe ser una página HTML que dice entre otras cosas una frase como esta: "Successfully exported 70 users to the file /home/juanmuno/usuarios (5526 bytes)." Veremos para que nos va a servir guardar esa salida en un archivo.

Si todo funcionó, debemos observar los siguientes resultados:

Ubicados en "/home/juanmuno" debe existir un archivo llamado "usuarios" en donde está toda la información de TODAS las cuentas de usuarios del sistema.

En el directorio donde ejecuté el comando cURL, debemos tener un archivo llamado "salida.html". Si abrimos este archivo en un Browser, debemos ver un mensaje que diga: "Successfully exported 70 users to the file /home/juanmuno/usuarios (5526 bytes)."

No sobra decir que la información que pido verificar es con respecto al ejemplo. Usted debería tener algo similar según sus pruebas.

Si las verificaciones anteriores han sido exitosas, entonces ¡Happy Scripting!.

 

 

::[FASE 3 - SCRIPTING]::

El Shell Script para Linux y para Windows será en una próxima. La idea es que el Shell Script que hagamos para Windows, sea capaz de "halar" el archivo de usuarios para un directorio local en una máquina con sistema operativo Windows. Veremos en la segunda parte de este artículo.

 

 

::[LO DEL OTRO COSTAL]::

Muchas cosas, por ejemplo un tema bien importante al hablar de cookies es precisamente el tiempo de validéz de una cookie. También se queda en el "otro costal" hablar un poco más de esos caractéres especiales en los URLs. Se queda, para una proxima, hablar de cURL y SSL. Como ven, hay más tema. Veremos como fluye el tiempo.

 

 

::[RECURSOS, REFERENCIAS Y LECTURAS RECOMENDADAS ]::

- cURL: http://curl.haxx.se/. Disponible para Windows y Linux.

- Achilles Local Proxy: http://i.b5z.net/i/u/1268303/f/tools/achilles_0_27.zip

- RFC 2396: URI Sintaxis. http://www.ietf.org/rfc/rfc2396.txt

- Open SSL: Para hacer que cURL soporte SSL. http://www.openssl.org/

- Shiflett Chris, HTTP Developers Handbook. Sams Publishing. ISBN: 0-672-32454-7

- The Art Of Scripting HTTP Request Using Curl. http://curl.haxx.se/docs/httpscripting.html

 

 

::[FINAL]::

Por ahora cerramos aquí esta entrega. Esperemos que el tiempo fluya para continuar con la FASE 3 de este problema. Se recibe cualquier comentario!.

Happy scripting!

Juan Felipe Muñoz - Fernández

Comments

Gracias

Exelente material que usted tiene en esta pagina soy usuario de fedora 4
iniciandome en Linux, tengo problemas al configurar postfix me da un error Unable to connect to POP server prevedis.com.
Error sending password: -ERR [AUTH] Invalid login

Y aun no lo puedo solucionar me puede por favor ayudar con algunos comandos que me puedan ayudar.