miércoles, 17 de octubre de 2012

Ejecutar comandos personalizados de Django desde el cron

Para poder ejecutar comandos personalizados de django desde el cron, necesitaremos aplicar el siguiente parche (si es que aún no lo trae):




Una vez aplicado el parche, ya podremos invocar nuestro comando de la siguiente manera:

minutos hora * * * /usr/bin/python /sitio/proyecto/django/manage.py comando



miércoles, 10 de octubre de 2012

Definir rango de puertos del ftp en alfresco 3.2

Debido a que el servicio de ftp de alfresco funciona en modo pasivo, este abrirá puertos por encima del 1024 para llevar a cabo la comunicación de datos.

Si tenemos un firewall muy restrictivo, nos interesará definir un rango determinado de puertos y abrir sólo ese rango.

Para definir el rango de puertos debemos añadir a /tomcat/shared/classes/alfresco-global.properties los siguientes parámetros:

ftp.dataPortFrom=50000
ftp.dataPortTo=60000

En este caso estamos definiendo el rango del 50000 al 60000.


Veamos si esto funciona de verdad. Hacemos un ftp en modo debug a nuestro servidor:

ftp -d 192.168.60.13 2122

Connected to 192.168.60.13.
220 FTP server ready
ftp: setsockopt: Bad file descriptor
Name (servidor:rafa): usuario
---> USER usuario
331 User name okay, need password for usuario
Password:
---> PASS XXXX
230 User logged in, proceed
---> SYST
215 UNIX Type: Java FTP Server
Remote system type is UNIX.

Indicamos el modo pasivo:

ftp> passive
Passive mode on.

Y lanzamos un comando:

ftp> ls
ftp: setsockopt (ignored): Permission denied
---> PASV
227 Entering Passive Mode (192,168,60,13,211,39)
---> LIST
150 File status okay, about to open data connection
drw-rw-rw-   1 user group 0 Jan  1  1970 Alfresco
drw-rw-rw-   1 user group 0 Jan  1  1970 AVM
226 Closing data connection
ftp>




Vemos como efectivamente el puerto que ha utilizado está por encima del 50000 y por debajo del 60000 (el puerto se obtiene de los valores que van después de la ip, 211*256+39=54055).

Si hacemos un tcpdump en el servidor, filtrando por ip origen, veremos que efectivamente ese es el puerto que ha utilizado:


Para puerto de datos:

10:40:20.810783 Out MAC ethertype IPv4 (0x0800), length 68: 192.168.60.13.54055 > ip_local.50958: . ack 2 win 46 <nop,nop,timestamp 552972262 76243556>

Para puerto de conexión:

10:40:20.810795  In MAC ethertype IPv4 (0x0800), length 68: ip_local.50583 > 192.168.60.13.2122: . ack 271 win 115 <nop,nop,timestamp 76243556 552972260>

lunes, 27 de agosto de 2012

Error al configurar Oracle Enterprise Manager Database Control

Al instalar Oracle 11gR2 en Ubuntu 11.04, me saltó un error en la parte de configuración del Database Control. No le presté mucha atención y posteriormente la intenté configurar lanzando:

emca -config dbcontrol db

pero tras introducir los datos, me volvió a escupir el mensaje de error:

27-ago-2012 12:25:57 oracle.sysman.emcp.EMConfig perform
INFO: Esta operación se está registrando en /u01/app/oracle/cfgtoollogs/emca/orcl/emca_2012_08_27_12_25_44.log.
27-ago-2012 12:25:58 oracle.sysman.emcp.EMConfig perform
GRAVE: Fallo al asignar puertos en los rangos especificados para los siguientes procesos: JMS [5540-5559],RMI [5520-5539],Database Control [5500-5519],EM Agent [3938] | [1830-1849]
Consulte el archivo log en /u01/app/oracle/cfgtoollogs/emca/orcl/emca_2012_08_27_12_25_44.log para obtener más información.
No se ha podido terminar la configuración. Consulte el archivo log en /u01/app/oracle/cfgtoollogs/emca/orcl/emca_2012_08_27_12_25_44.log para obtener más información.


El problema no estaba en los puertos, pues todos los rangos estaban libres. Googleando un poco conseguí encontrar la solución, que estaba en la resolción de nombres de la máquina. Es decir, para la configuración del Database Control, nuestro equipo debe ser capaz de resolver tanto localhost como nuestro hostname a la ip 127.0.0.1, por tanto, hay que tener algo así en nuestro /etc/hosts:


127.0.0.1 localhost.localdomain localhost
127.0.0.1 hostname.domain.com hostname

Una vez finalizada la instalación, puedes volver a configurar para que resuelva el hostname a tu propia ip.

viernes, 20 de julio de 2012

subprocess en python

Vamos a ver cómo hacer un script de parada/arranque de un servicio utilizando subprocess.

subprocess nos va a permitir lanzar un comando y esperar a que este termine, y una vez terminado, ver en qué estado ha finalizado.

El siguiente ejemplo se puede utilizar para llevar a cabo un reinicio automático de un servicios (jboss por ejemplo) y estar seguros de que el servicio es detenido y arrancado correctamente:

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

import subprocess
script_arranque='/etc/init.d/jboss start'
script_parada='/etc/init.d/jboss stop'
#paramos jboss
pipe=subprocess.Popen(script_arranque, stdout=subprocess.PIPE, shell=True)
estado=pipe.wait()
out, err = pipe.communicate()
if estado == 0:
        print "Estado salida correcto."
else:
        print "Salida de error: " + str(err) 
'''en este caso, el único proceso java que corre es jboss, si hubiese más de uno, la siguiente opción no sería válida ' ' '
pipe=subprocess.Popen('pidof java', stdout=subprocess.PIPE, shell=True)
out, err = pipe.communicate()
pid = out.strip()
if pid != '':
        print "El proceso no se ha detenido, matamos el pid: " + pid + "."
        pipe=subprocess.Popen('kill -9 ' + pid, stdout=subprocess.PIPE, shell=True)
#Ya está parado jboss, ahora lo arrancamos
pipe=subprocess.Popen(script_parada, stdout=subprocess.PIPE, shell=True)
estado=pipe.wait()
out, err = pipe.communicate()
if estado == 0:
        print "Estado salida correcto."
else:
        print "Salida de error: " + str(err)


Un detalle a tener en cuenta cuando utilicemos subprocess es que si utilizamos la shell (shell=True) el comando que pasemos será una cadena, mientras que si no utilizamos la shell (shell=False) el comando se ha de pasar como una lista. Por ejemplo, para ejecutar un ls -la:

Con shell:
    subprocess.Popen('ls -la', shell=True)
Sin shell:
    subprocess.Popen(['ls','-la'], shell=False)


Para ver el estado en el que finaliza, podemos hacerlo mediante:

estado=pipe.wait()

ó

estado=pipe.returncode


Y para ver la salida estándar y la salida de error, haremos uso de communicate:

out, err = pipe.communicate()

Envío de correo en python bajo SSL

Si necesitáis enviar correos con python por ssl de una forma sencilla, recomiendo el uso de pyzmail (http://www.magiksys.net/pyzmail/). Para instalar pyzmail, lo podéis hacer directamente con pip:

pip install pyzmail

Si no tenemos instalado pip, para instalarlo:

wget http://python-distribute.org/distribute_setup.py 
python distribute_setup.py 
easy_install pip

Os dejo un sencillo código de ejemplo:

# -*- coding: iso-8859-15 -*- import pyzmail #Componemos el correo sender=('Yo','cuenta@remitente.es') recipients=['cuenta@destinatario.es',] subject='Prueba envio SSL' text_content='Este correo ha sido enviado bajo SSL' prefered_encoding='iso-8859-1' text_encoding='iso-8859-1' #Vamos a adjuntar dos ficheros fichero=open('fichero.txt.tar.gz', 'rb').read() fichero2=open('fichero.txt','rb').read() payload, mail_from, rcpt_to, msg_id=pyzmail.compose_mail( sender, recipients, subject, prefered_encoding, (text_content, text_encoding), html=None, attachments=[(fichero, 'application', 'octet-stream', 'fichero.tar.gz', 'us-ascii'),(fichero2, 'application', 'octet-stream', 'fichero.txt', 'us-ascii')]) #Datos de configuracion para el envio smtp_host='host' smtp_port=puerto para comunicacion ssl smtp_mode='ssl' smtp_login='cuenta@remitente.es' smtp_passwd='password' #Enviamos el correo ret=pyzmail.send_mail(payload, mail_from, rcpt_to, smtp_host, smtp_port=smtp_port, smtp_mode=smtp_mode, smtp_login=smtp_login, smtp_password=smtp_passwd) if isinstance(ret, dict): if ret: print 'fallo en los destinatario:', ', '.join(ret.keys()) else: print 'correcto' else: print 'error:', ret

Obtener informacion de repositorios a través de los metadatos .git publicados por error

 A raiz de CTF realizado recientemente, me ha parecido interesante publicar este post sobre los errores de seguridad que se encuentran en mu...