Trabajando con Ruby On Rails me ha tocado escribir código usando HAML. Particularmente no me agrada mucho (entre otras cosas porque no tiene soporte multilínea, porque no identa correctamente las cadenas de texto plano, porque agrega otra capa más de interpretación a la aplicación, etc) pero cuando toca usarlo es bueno hacerlo con un buen soporte. Y cuando hablo de soporte me refiero al resaltado de sintaxis.

Para escribir código usualmente uso un editor de texto (Gedit o Geany), así que en ésta receta explicaré como agregar soporte para el resaltado de sintaxis en Gedit.

Primero agregamos soporte para que las extensiones usadas comúnmente en Rails sean reconocidas por el sistema. Abrimos una terminal y escribimos:

wget http://dl.dropbox.com/u/16349833/rails.xml 
sudo cp rails.xml /usr/share/mime/packages/rails.xml
sudo update-mime-database /usr/share/mime

Luego agregamos los archivos de definición de sintaxis en la carpeta del sourceview de GTK ejecutando:

wget http://dl.dropbox.com/u/16349833/gedit_rails_syntax.zip
sudo unzip gedit_rails_syntax.zip -d /usr/share/gtksourceview-2.0/language-specs


Ahora con nuestro editor de texto favorito (y como root) abrimos el archivo /usr/share/gtksourceview-2.0/language-specs/ruby.lang para modificar el sourceview de GTK y agregar soporte para nuevas extensiones. Buscamos la línea:

*.rb

Y la cambiamos por:

*.rb;*.rake;*.rjs

Por último, abrimos el archivo /usr/share/gtksourceview-2.0/language-specs/html.lang y buscamos la línea que dice:

*..html;*.htm

Y la cambiamos por:

*.html;*.htm;*.erb;*.rhtml

Cerramos todas las instancias de Gedit y al abrir de nuevo ya nuestro código HAML debería verse resaltado.


Existen recetas que instalan una serie de plugins (con soporte para haml, rjs, etc) y te dejan al Gedit como TextMate, pero como no me gusta TextMate entonces prefiero hacerlo a patica xD

Espero que la receta les haya servido de ayuda.

Referencias:
http://groups.google.com/group/haml/browse_thread/thread/6c8babd81a46b6b8/b5100d80d9182c71?pli=1
http://blog.adsdevshop.com/2008/04/19/erb-syntax-highlighting-in-gedit/

After almost a year without publishing a single post, it seems this week I’m going to beat all my records.

A week ago, I wanted to prank my brother for a while. Nothing sophisticated… just some Iptables rules, Tinyproxy and HTTP magic. To go ahead with my evil plans, I needed “something” able to redirect a HTTP request. Actually, there are several ways to do that: Apache redirects, Tornado, Netcat* and so on. These alternatives are fast, bulletproof and time-saving, but not fun.

As many of you probably know, I didn’t get a job yet. That necessary means that I’ve got plenty of free time to waste. So… what did I do? I wrote some Perl and today I’m publishing the source code just in case someone finds it useful somehow. Like the previous entry, it’s published in the public domain.

The script just collects connections, issues 301 back (Moved Permanently) and sets Location to the URI specified as a command line argument (option -u). It lacks some security checks (left as an exercise to the reader) but it does what it is supposed to do. You may likely spot some silly bugs as I haven’t spent much time reading it again. Reports are welcome!

For those wondering, the prank was a big success. I’m afraid I can’t spare any detail by now but it turns out my bro is still thinking that his computer has been cracked.

Example invocation:

$ perl redir.pl -p 7070 -v -t 3 -u http://31337.pl
2011/02/24 21:41:54 Listening on port 7070
2011/02/24 21:41:54 Redirecting HTTP requests to: ‘http://31337.pl’
2011/02/24 21:41:54 3 thread(s) working under the hood

And finally the source code:

use warnings;
use threads;
 
use Thread::Queue;
use POSIX;
 
use IO::Socket::INET;
use HTTP::Request;
use HTTP::Status qw(:constants status_message);
 
use Getopt::Long;
use DateTime::Format::HTTP;
use Data::Validate::URI qw(is_http_uri);
use Log::Log4perl qw(:easy);
 
use constant MAX_THREADS => 10;
use constant MAX_LEN_HEADERS_BUFFER => 8*1024;
use constant DEFAULT_REDIRECT_URI => "http://www.example.org";
use constant DEFAULT_PORT => 80;
use constant DEFAULT_POOL_SIZE => 3;
 
my $redir_uri = DEFAULT_REDIRECT_URI;
my $server_port = DEFAULT_PORT;
my $thread_pool_size = DEFAULT_POOL_SIZE;
my $verbose;
 
GetOptions('url=s' => \$redir_uri, 
           'port=i' => \$server_port,
           'threads=i' => \$thread_pool_size,
           'verbose'  => \$verbose) or exit -1;
 
die "Invalid redirect URI (e.g. http://www.example.org)\n" unless is_http_uri($redir_uri);
die "Invalid port (e.g. 8080)\n" unless 0 < $server_port && $server_port < 2**16;
die "Invalid pool size (should be in [1..".MAX_THREADS."])\n" 
            unless 0 < $thread_pool_size && $thread_pool_size <= MAX_THREADS;
 
Log::Log4perl->easy_init( level => $verbose? $DEBUG : $INFO );
 
my $pending = Thread::Queue->new(); 
 
my $lsock = IO::Socket::INET->new( LocalPort => $server_port,
                                   Proto => 'tcp',
                                   Listen => 1,
                                   Reuse => 1 ) or die "Couldn't bind listening socket ($!)\n"; 
 
INFO("Listening on port $server_port\n");
INFO("Redirecting HTTP requests to: '$redir_uri'\n");
 
my @workers = ();
for (1..$thread_pool_size) {
    if ($thread = threads->create("worker")) {
        push(@workers, $thread);
    }
}
 
DEBUG(sprintf("%d thread(s) working under the hood\n", $#workers+1));
 
# Set a tidy shutdown just in case an external agent SIG{INT,TERM}s the process
$SIG{'INT'} = $SIG{'TERM'} = sub {
    # Dirty hack. threads->kill() does not wake up the thread :(
    for (1..@workers) {
        $pending->enqueue(-1);
    }
    for (@workers) {
        DEBUG(sprintf("Worker %d terminated: %d clients served\n", $_->tid, $_->join())); 
    }
    close($lsock); 
    exit 0; 
};
 
while(1) {
    my $csock = $lsock->accept() or next;
    $pending->enqueue(POSIX::dup(fileno $csock));
    DEBUG(sprintf("New client enqueued: %s:%s\n", $csock->peerhost, $csock->peerport));
    close($csock);
}
 
sub worker {
    my $clients_served = 0;
    while(my $fd = $pending->dequeue) { # API promises thread safety :-)
        if ($fd == -1) {
            return $clients_served;
        }
 
        my $sock = IO::Socket::INET->new_from_fd($fd, "r+");
        DEBUG(sprintf("Dequeued client %s:%d by worker %d.\n", $sock->peerhost,
                            $sock->peerport, threads->tid()));
 
        my $buf = "";
        while(<$sock>) {
            # CAUTION: there isn't any self protection against very long lines
            last if /^\r\n$/;
            $buf .= $_;
            goto BYE if length $buf > MAX_LEN_HEADERS_BUFFER;
        }
 
        if (my $request = HTTP::Request->parse($buf)) {
            INFO(sprintf("[%s] %s {%s}\n", $request->method, $request->uri, $sock->peerhost));
        }
 
        printf $sock "HTTP/1.1 %d %s\r\n", 
            HTTP_MOVED_PERMANENTLY, status_message(HTTP_MOVED_PERMANENTLY);
        printf $sock "Date: %s\r\n", DateTime::Format::HTTP->format_datetime;
        print $sock "Location: $redir_uri\r\n";
        print $sock "Server: Simple HTTP Redirection/0.1 ($^O)\r\n";
        print $sock "Connection: close\r\n";
        print $sock "\r\n";
 
BYE:  
        $clients_served++;
        close($sock);
    }
}

(*) just an approach, may drop connections:

while [ 1 ]; 
 do echo -e "HTTP/1.1 301 Moved Permanently\r\nLocation: http://31337.pl\r\n\r\n" | nc -l 7070; 
done

This introduction is followed by some Python code (function evaluate_postfix_expr) to evaluate expressions (only integers, but may be extended with ease) in Reverse Polish Notation (RPN). Some simple tests are also included in the bundle.

I agree it’s a little useless, but I thought it might be useful for someone (CS students maybe?). If you want to examine the stack in each iteration you only have to turn debugging on. That can be accomplished by changing logging.INFO to logging.DEBUG (line 7).

Copy, distribute or do whatever you want with it. It’s released in the public domain.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#!/usr/bin/env python
 
import logging
import re
import unittest
 
logging.basicConfig(level=logging.INFO)
 
operators_table = {'+': int.__add__, 
             '-': int.__sub__,
             '*': int.__mul__,
             '/': int.__div__,
             '^': int.__pow__}
 
class ExpressionError(Exception):
    def __init__(self, message):
        self._message = "Expression error: %s" % message
    def _get_message(self): 
        return self._message
    message = property(_get_message)
 
class TestEvaluation(unittest.TestCase):
    def test_correct(self):
        self.assertEqual(666, evaluate_postfix_expr("666"))
        self.assertEqual(2+3-6, evaluate_postfix_expr("2 3 + 6 -"))
        self.assertEqual(2*3+4, evaluate_postfix_expr("2 3 * 4 +"))
        self.assertEqual(2*(3+4), evaluate_postfix_expr("2 3 4 + *"))
        self.assertEqual(3**4, evaluate_postfix_expr("3   3  *     3  *      3 *"))
        self.assertEqual((7/2)**4, evaluate_postfix_expr("7 2 / 4 ^"))
        self.assertEqual((2**3)**4, evaluate_postfix_expr("2 3 ^ 4 ^"))
        self.assertEqual(5+((1+2)*4)-3, evaluate_postfix_expr("5 1 2 + 4 * 3 - +"))
 
    def test_malformed(self):
        self.assertRaises(ExpressionError, evaluate_postfix_expr, "+")
        self.assertRaises(ExpressionError, evaluate_postfix_expr, "2 +")
        self.assertRaises(ExpressionError, evaluate_postfix_expr, "+ 2 2")
        self.assertRaises(ExpressionError, evaluate_postfix_expr, "2 2")
        self.assertRaises(ExpressionError, evaluate_postfix_expr, "2 2 + -")
        self.assertRaises(ExpressionError, evaluate_postfix_expr, "a 2 -")
 
def evaluate_postfix_expr(expr):
    atoms = re.split(r"\s+", expr)
    stack = [] 
    for atom in atoms:
        if atom in ["+", "-", "*", "/", "^"]:
            try:
                op2 = stack.pop()
                op1 = stack.pop()
            except IndexError:
                raise ExpressionError("Too few operands (unbalanced)")
            logging.debug("Calculating %d %s %d" % (op1, atom, op2))
            atom = operators_table[atom](op1, op2)
        else:
            try:
                atom = int(atom)
            except ValueError:
                raise ExpressionError("Unable to parse '%s' as integer" % atom)
 
        try:
            stack.append(atom)
        except MemoryError:
            raise ExpressionError("Too long expression")
 
        logging.debug("Pushed element %d. Stack status: %s" % (atom, stack))
 
    if len(stack) == 1:
        return stack.pop()
    else:
        raise ExpressionError("Too many operands (unbalanced)")
 
if __name__ == "__main__":
    unittest.main()

Hace un par de semanas me asignaron una laptop nueva en el trabajo, cambie mi Lenovo T60 por una T410 que en general es mucho mas rápida. La nueva tiene 4GB de RAM por lo que preferí instalar Fedora 64 bits, todo me funciono sin problemas excepto por el ajuste del brillo de la pantalla, investigando un poco conseguí el controlador de vídeo como lo pueden ver aquí:

lspci | grep VGA
01:00.0 VGA compatible controller: nVidia Corporation GT218 [NVS 3100M] (rev a2)
Ajuste de brillo de pantalla en Fedora 14 para una laptop Lenovo T410

Luego de instalare los controladores privativos de nVidia me puse a probar las teclas especiales y note que no podía ajustar el brillo de la pantalla, cosa que es una molestia en especial si te toca estar de guarida y te llaman a las 3am por que el servidor XYZ reporta cargas altas. Luego de investigar un poco comparar versiones distintas de xorg.conf, encontré la solución. En la sección Device es necesario agregarle la opción RegistryDwords y la variable EnableBrightnessControl con el valor 1. La sección Device queda así:

Section "Device"
  Identifier     "Device0"
  Driver         "nvidia"
  VendorName     "NVIDIA Corporation"
  Option "RegistryDwords" "EnableBrightnessControl=1"
EndSection

Mi archivo de configuración xorg.conf completo puede ser descargado desde este link.

Esta es la continuación de otro  artículo de hace más o menos un año , en estos días en Debian unstable ha entrado una nueva versión del kernel (2.6.37) y las anteriores fuentes ya no compilan. Las nuevas instrucciones quedan así (el nuevo parche disponible  aquí ): 1.- Descargar nueva rama v4l: hg clone http://mercurial.intuxication.org/hg/s2-liplianin/ cd s2-liplianin zcat s2-liplianin-af9035-af9033.diff.gz | patch -p1 2.- Añadir al v4l/.config estas líneas: ############################### CONFIG_DVB_AF9033=m CONFIG_DVB_USB_AF9035=m CONFIG_MEDIA_TUNER_TUA9001=m ##############################   3.- Compilar make   4.- Instalar en un temporal make install DESTDIR=`pwd`/tmp 5.- Copiar al directorio de módulos del kernel sudo cp -ra tmp/lib/modules/$(uname -r)/kernel/drivers/media/ \             /lib/modules/$(uname -r)/updates/v4l sudo depmod -a 6.- Reiniciar y disfrutar (del hardware porque de la tele últimamente no mucho)   UPDATE . Para el kernel 2.6.38 nuevo parche:  aquí

Con la salida de Debian GNU/Linux 6.0 el equipo de canaima se complace en presentar la primera versión de pruebas de Canaima GNU/Linux 3.0, pueden revisar la nota oficial en el siguiente enlace:

http://canaima.softwarelibre.gob.ve/descargas/canaima-cdnvivo/releases/3.0

Una vez mas se le hace un llamado a toda la comunidad a que participe, pruebe y reporte cualquier problema con la distro.

Nota: Quiero agradecer (una vez mas)  la inclusión de mi nombre en los créditos de la distribución, es un verdadero placer colaborar con el desarrollo del Sistema Operativo Nacional.

Creditos en Canaima 3.0

Gracias a las redes sociales de microbloging (identi.ca y twitter) el pasado sábado fuimos testigos del nacimiento en tiempo real de Debian GNU/Linux 6.0 conocido en el bajo mundo como “squeeze”. Fue muy interesante ver los updates de los pasos que se estaban ejecutando en vivo, como sincronizaciones e imágenes por arquitectura. En total se generaron 693 imágenes ISO.

Estas son algunas de sus características:

  • el entorno de escritorio KDE 4.4.5
  • el entorno de escritorio GNOME 2.30
  • el entorno de escritorio Xfce 4.6
  • el entorno de escritorio LXDE 0.5.0
  • X.Org 7.5
  • OpenOffice.org 3.2.1
  • GIMP 2.6.11
  • Iceweasel 3.5.16 (una versión de Mozilla Firefox que no utiliza la marca registrada)
  • Icedove 3.0.11 (una versión de Mozilla Thunderbird que no utiliza la marca registrada)
  • PostgreSQL 8.4.6
  • MySQL 5.1.49
  • la Colección de compiladores de GNU 4.4.5
  • Linux 2.6.32
  • Apache 2.2.16
  • Samba 3.5.6
  • Python 2.6.6, 2.5.5 and 3.1.3
  • Perl 5.10.1
  • PHP 5.3.3
  • Asterisk 1.6.2.9
  • Nagios 3.2.3
  • el Hipervisor Xen 4.0.1 (con soporte tanto para dom0 como para domU)
  • OpenJDK 6b18
  • Tomcat 6.0.18
  • más de 29,000 paquetes de programas listos para usarse construidos a partir de 15.000 paquetes fuente).

Debian 6.0 incluye cerca de 10,000 paquetes nuevos como el navegador Chromium, la solución de monitorización Icinga, la interfaz de usuario para administración de paquetes Software Center, el administrador de red wicd, las herramientas de contenedor de Linux lxc y el entorno para clústers Corosync.

Para mas información: http://www.debian.org/News/2011/20110205a

Cuando uno habla de hacking o hacks, la mayoría de la gente lo asocia con el típico nerd que vive con su mama y que desde el sótano de su casa irrumpe en otras computadoras. En este articulo voy a hablar un poco de las herramientas disponibles para hacer precisamente eso, pero por motivos didácticos, así que no soy responsable de sus acciones. La mayoría de ustedes han escuchado de nmap y nessus pero que hay de las otras herramientas? echemosle un vistazo y juguemos un poco con la red.

La preferida por muchos es tcpdump, es una herramienta que simplemente nos permite escuchar todo el trafico de la red y graba todos estos paquetes para que luego los podamos analizar. Si tienes mas de una NIC, puedes especificar por cual quieres escuchar pasándole el parámetro -i interfaz. Una cosa que me gusta es que tcpdump pone tu NIC en modo promiscuo (o por lo menos intenta hacerlo) de forma predeterminada, de esta forma puede escuchar todo el trafico de ese segmento de la red. Para deshabilitar el modo promiscuo y limitar el trafico solo a el que le compete a tu NIC puedes usar el parámetro -p. Hay muchos otros parámetros que puedes usar, recuerda ejecutar man tcpdump para mas información.

Aquí les dejo un video que muestra como saber que sitios web estan visitanto desde nuestra red.


Ahora bien, vamos a cuidar nuestras espaldas y supongamos que queremos saber que ordenadores están en tu segmento de red pero queremos evitar enviar paquetes a la red preguntando por estos ordenadores para que no nos delate (recuerda, este tipo de actividad le puede parecer sospechoso al administrador). La herramienta indicada para esta tarea es p0f, esta usa técnicas pasivas para tratar de adivinar que sistemas existen en tu segmento de red y al igual que tcpdump permite especificar la interfaz a usar y grabar trafico guardándolo en un archivo estilo tpcdump.

Nuestras dos herramientas se empiezan a diferenciar a la hora de definir de forma predeterminada el estado de promiscuidad de nuestra NIC, p0f requiere que especifiques que quieres que la NIC este en modo promiscuo y solo escucha cuando un ordenador en nuestra red abre nuevas conexiones. Aquí una lista de parámetros útiles para p0f.

  1. -i Especifica la NIC por la que va a escuchar (p0f -i eth0)
  2. -w Guarda la salida en formato tcpdump (p0f -i eth0 -w laboratorio.dump)
  3. -o Al igual que -w guarda la salida de este comando pero en un archivo de texto sin formato tcpdump
  4. -O Proporciona una salida mas descriptiva. Tambien llamado modo ACK
  5. -p Indica que quieres que ponga la NIC en modo promiscuo (p0f -i eth0 -p)
  6. -s Analiza un archivo que previamente capturaste en formato tcpdump

El problema de todo esto hasta ahora es que es muy probable que el resto de las maquinas esten bajo una NAT y no podamos verlas como tal, solo veremos el router. Uno puede usar el parámetro -M que le indica a p0f que use un algoritmo de detección de enmascaramiento e intenta identificar estas maquinas individualmente.

Supongamos que ya sabemos cuales son los otros ordenadores que existen en nuestra red, ahora lo interesante es saber que tipo de trafico tienen, sera FTP? o tal vez HTTP?, POP?, IMAP? o cualquier otro que sea de nuestro interés. Lo segundo que en mi caso me llama la atención es ver desde donde viene este trafico, con quien se comunican estos otros ordenadores? para responder todo esto podemos usar nuestra tercera herramienta, dsniff.

Esta utilidad al igual que las anteriores nos permite especificar que interfaz queremos usar e incluso podemos usar el parámetro -p para que use archivos que han sido grabados previamente. Puedes habilitar la detección automática de protocolos usando el parámetro -m lo que te va dar detalles crudos de que hacen tus vecinos de red.

La salida de este comando luce algo asi:

~# dsniff -m
dsniff: listening on eth0
-----------------
02/01/11 09:50:19 tcp 10.153.212.26.46004 -> trillian.gtlib.gatech.edu.21 (ftp)
USER anonymous
PASS mailto:axel-devel@lists.alioth.debian.org

-----------------
02/01/11 09:51:50 tcp 10.153.212.26.48257 -> linux.nssl.noaa.gov.21 (ftp)
USER anonymous
PASS mailto:axel-devel@lists.alioth.debian.org

-----------------
02/01/11 09:53:06 tcp 10.153.212.26.39551 -> chernabog.cc.vt.edu.21 (ftp)
USER anonymous
PASS chrome@example.com

Ahora que sabemos quienes están a nuestro alcance, que hacen y con quien, podemos revisar la seguridad de los servicios que prestan, el mas común es el servicio web.

Una herramienta buena para revisar como esta la seguridad de nuestro servidor web es nitko. Puedes seleccionar el hostname con la opción -h incluso puedes pasarle una lista de host o IPs en un archivo de texto. nitko se enfoca en el puerto 80 de forma predeterminada pero puedes alterar esto usando el parámetro -p de hecho tiene un montón de parámetros que puedes usar para pruebas de seguridad especificas... mas de las que quisiera mencionar aquí.

No quería terminar este articulo sin antes mencionar chkrootkit, esta utilidad nos permite analizar sistemas y trata de terminar si han sido manipulados, para ver una lista de las pruebas disponibles puedes usar el parámetro -l. Útil para verificar si el sistema ha sido infectado o si tiene rootkits.

Este articulo es para fines didácticos, para que 'juegues' en tu propia red y no para que dañes sistemas ajenos ni adquieras a información que no te pertenece.

Hacía tiempo que programar me aburre (según que cosas claro) pero el fin de semana pasado me lo he vuelto a pasar como un niño escribiendo código.   Problema:   En la Consejería de Educación de la Comunidad de Madrid han empezado a usar un nuevo invento llamado Multiseat ( Microsoft lo llama Multipoint ) que consiste en unos pequeños aparatos que de una forma lógica vienen a ser un HUB USB que contiene una tarjeta de vídeo, una tarjeta de sonido, y 4 puertos USB, si conectamos varios (pongamos seis) en un equipo automáticamente multiplicamos los puestos disponibles en ese equipo (por USB conectamos un teclado y un ratón a cada Multiseat) (puedes  ver algún detalle más en la web de Thinetic Systems )   El cómo hicimos andar todo este montaje es otra historia que algún día contaré, pero lo que hoy nos centra es un pequeño problema, y es la gestión de los dispositivos de almacenamiento que se conectan a los puertos USB del Multiseat, para que todos lo entendamos, cuando conectamos una memoria USB se conecta físicamente al servidor (con un HUB USB por el medio) y teníamos que inventar una manera de que sólo pudiera verlo/usarlo el usuario sentado directamente en ese puesto. Ya os adelanto que en Microsoft aún no lo han conseguido (que yo sepa) .   Solución:   En los sistemas basados en Linux durante los últimos años se han venido usando distintas soluciones para el automontaje de discos extraibles (usbmount, HAL, DeviceKit), ahora estamos en la era de  UDisk . Es un software que se conecta al gestor de dispositivos del kernel (udev) mediante unas reglas (/lib/udev/rules.d/80-udisks.rules) y crea un bus de sistema (en dbus) donde expone todo lo que encuentra, así las aplicaciones que quieran gestionar un dispositivo sólo tienen que escuchar esos eventos.   UDisks permite inhibir el montaje (sigue reconociendo lo que enchufamos pero advierte en dbus que está inhibido y no realiza ninguna acción) por lo que no se montan los dispositivos automáticamente, a este inhibidor se le puede pasar un comando que cuando termine deje de inhibir... un ejemplo de uso práctico es el asistente de instalación gráfico que usa Ubuntu (ubiquity) y que inhibe el montaje de dispositivos (por razones obvias) durante la modificación de particiones y la instalación.   Nuestra primera aplicación a desarrollar es un demonio que se conecte al bus del sistema, escuche los dispositivos que se conectan y desconectan, leemos sus propiedades y a partir de ellas adivinamos (por el DEVPATH) en que puesto Multiseat se ha conectado para entonces montarlo con privilegios exclusivos para ese usuario y crearle un icono en el escritorio para que pueda desmontarlo. Este demonio decidí programarlo en python y lo bauticé como  multiseat-udisks.py  se ejecuta cuando (al arranque) encuentra los puestos MultiSeat (subcarpetas en /dev/usbseat)   Ya tenemos solucionado que los dispositivos de almacenamiento se automonten en su sitio y con sus permisos, ahora viene cuando el usuario quiere extraerlo, GNOME crea un icono en el escritorio con nuestro pendrive, realmente no es un archivo y con el inhibidor por el medio no lo va a crear por lo que modifiqué multiseat-udisks.py para que crease un lanzador *.desktop especial con la línea mágica « X-multiseat-desktop=x » siendo x el puesto donde esta montado (subcarpeta de /dev/usbseat ).   Para desmontar tenemos dos problemas, primero el usuario no es root y como el dispositivo no está en fstab no le va a dejar desmontarlo, y segundo ese icono del escritorio nos permite abrir el contenido del dispositivo de memoria pero no extraerlo de manera segura (sync && umount) lo primero que se me ocurrió es hacer una extensión para Nautilus (gestor de archivos de GNOME) para que cuando se haga click derecho sobre un archivo *.desktop busque la línea mágica y, si existe, añada una entrada a ese menú derecho del tipo « Desmontar dispositivo extraíble multiseat », cuando se pulse sobre esa opción se llama al proceso de desmontar. Esta extensión (también escrita en Python) la bauticé como  nautilus-umount-multiseat.py     Para el problema de los privilegios tuve que programar la tercera ficha de este puzle, una pequeña aplicación en C (instalada con bit SUID) y que eleva privilegios a root para llamar al comando de desmontaje  umount.multiseat.c . Muchas aplicaciones de montar y desmontar (instaladas en /sbin) van con el BIT SUID por lo que me parece una manera bastante estandar de hacerlo y más teniendo en cuenta que los usuarios que usan MultiSeat pueden estar en un LDAP.   Cuando la extensión de Nautilus detecta que el icono es de un dispositivo conectado a un Multiseat, llama a esta aplicación que eleva los privilegios a root (mediante setuid(0) ) y llama a multiseat-udisks.py con 2 argumentos, el primero es el dispositivo montado (ejemplo: /dev/sdc1 ) y el segundo que se genera dentro del programa C es el UID (identificador numérico del usuario que quiere desmontarlo). El script multiseat-udisks hace una serie de comprobaciones para que los parámetros sean correctos y que el usuario pueda desmontar ese dispositivo (que el punto de montaje le pertenezca) lo desmonta y limpia tanto la carpeta donde se ha montado como el icono del escritorio.   El sistema lo hemos probado en varias instalaciones y funciona a la perfección, más tarde convertí el código en paquete *.deb y a instalar en los centros...   El motivo por el que me he vuelto a divertir programando es que nadie había hecho algo del estilo y la documentación que podía buscar por internet solo se centraba en el uso de cada herramienta o API por separado por lo que el desarrollo ha sido desde cero hasta algo terminado y funcionando.   Siento el tostón técnico pero a algunos nos gusta contar nuestras frikadas