"Después del juego es antes del juego"
Sepp Herberger

domingo, 20 de noviembre de 2016

Filtrar la salida a Internet de los PC mediante iptables

En los centros educativos muchas veces es necesario filtrar de forma temporal la salida a Internet en uno o varios PC para que los alumnos se centren en sus tareas. Aislar totalmente el equipo de la red (eliminando rutas o quitando la IP) es demasiado drástico y daría problemas si los PC montan el home por NFS o el usuario necesita recursos de la red del centro o la red educativa para trabajar (impresoras, intranet, Rayuela, etc).

Lo mas adecuado es filtrar todo tráfico que no tenga como destino la Red Educativa. En nuestro caso está red usa el espacio de direcciones 172.X.X.X, por lo que habría que desechar todo paquete que no tenga como destino direcciones en ese rango. La forma mas sencilla es usando iptables, con la orden:
# iptables -A OUTPUT -o eth0 ! -d 172.0.0.0/8 -j DROP
Con esto lo que hacemos es decir que todo paquete de salida por la interface eth0 que no tenga como destino (el simbolo ! es la negación) la red 172.0.0.0/8 debe ser descartado. Como consecuencia de esta regla no funciona ni siquiera el ping hacia fuera. Si queremos apretar un poco mas la cuerda y solo permitir el tráfico en nuestra red:
# iptables -A OUTPUT -o eth0 ! -d 172.20.196.0/24 -j DROP
Siendo nuestra red 172.20.196.X, claro está.

Con esta regla iptables tenemos, sin embargo, un problema cuando configuramos una red privada dentro de un aula que opera en el espacio de direcciones 192.168.0.X y sale hacia fuera mediante NAT. Los paquetes de esos PC con destino 192.168.0.X son descartados y por tanto la comunicación es imposible incluso para salir a la red del educativa. Si probamos a:
# iptables -A OUTPUT -o eth0 ! -d 172.0.0.0/8,192.168.0.0/24 -j DROP
Nos llevamos la desagradable sorpresa de que ! no es compatible con múltiples direcciones de destino. ¿Cómo lo hacemos entonces?. Mi compañero Oscar me dió la pista para usar un chain:
# iptables -N SOLO_INTRANET
# iptables -A SOLO_INTRANET -d 172.0.0.0/8 -j RETURN
# iptables -A SOLO_INTRANET -d 192.168.0.0/24 -j RETURN
# iptables -A SOLO_INTRANET -j DROP
# iptables -A OUTPUT -j SOLO_INTRANET  
Expliquemos: se crea una cadena (SOLO_INTRANET) que deja pasar trafico hacia 172.0.0.0/8 y 192.168.0.0/24, pero descarta el tráfico hacia cualquier otro lado, ya que las reglas se aplican secuencialmente. Luego vinculamos el chain SOLO_INTRANET al chain OUTPUT para que se aplique a los paquetes salientes. Y ya está.

Para borrar estos filtros haremos:
# iptables -F
Bueno, pues ya solo quedaría integrar estos comandos en los programas de gestión remota que usemos (p.e.: Aulalinex o epoptes) o bien en los scripts, crontabs o procesos desde donde queramos aplicarlos.

Al final los paquetes solo podrán ir, como muy lejos, a presidir la Comisión de Peticiones del Congreso. Y ojito, que les ponemos otro filtro si nos dejan.

viernes, 4 de noviembre de 2016

Desactivar el visualizador de PDF de Google Chrome

Bueno, pues en la entrada inmediatamente anterior contamos como desactivar el en ocasiones molesto visualizador de PDF embebido en el navegador Firefox. Veamos ahora lo propio para Chrome.

Si tenemos un solo usuario nada mas sencillo que escribir "about:plugins" en la barra del navegador e inhabilitar la extensión "Chrome PDF Viewer":


Si tenemos muchos usuarios esto no es evidentemente productivo y es una situación detestable para cualquiera de nosotros. Vamos a ver como hacerlo de forma masiva. Primero hay que buscar donde desactivarlo programatically como dicen los anglos o mediante un script, como se ha dicho aquí de siempre.

La primera mala noticia es que Google Chrome no tiene un fichero unificado global como /etc/firefox/syspref.js donde meter una configuración que afecte a todos los usuarios de una máquina. Hay que ir tocando home a home una configuración que no queda bloqueada y que el usuario puede cambiar cuando quiera.

El fichero de configuración es $HOME/.config/google-chrome/Default/Preferences, pero si intentamos verlo con un cat nos encontraremos con un texto ilegible en formato JSON. No creo que el fichero esté ofuscado aposta, simplemente a nadie se le ocurrió que tendría que leerlo un humano.

Para examinarlo primero debemos hacer beautifying del código o "ponerlo bonito" dicho en castizo. Una forma rápida es instalar el programita "jq" y haciendo:
# apt-get install jq
# jq '.' /home/rutaamihome/.config/google-chrome/Default/Preferences 
Con esto veremos todo mucho mas claro. El programa jq es a JSON lo que xmlstarlet a XML: una herramienta especializada de línea de comandos para manejar este formato, ideal para ser usada en scripts.

Bueno, pues navegando por dicho fichero, que es montruosamente grande, vemos este atributo JSON:
......
  "plugins": {
    "last_internal_directory": "/opt/google/chrome",
    "plugins_list": [
      {
        "enabled": true,
        "name": "Chrome PDF Viewer",
        "path": "chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/",
        "version": ""
      },
      {
        "enabled": true,
        "name": "Shockwave Flash",
        "path": "/home/staff/infoadmin/.config/google-chrome/PepperFlash/23.0.0.185/libpepflashplayer.so",
        "version": "23.0.0.185"
      },
      {
        "enabled": true,
        "name": "Widevine Content Decryption Module",
        "path": "/opt/google/chrome/libwidevinecdmadapter.so",
        "version": "1.4.8.893"
      },
      {
        "enabled": true,
        "name": "Native Client",
        "path": "/opt/google/chrome/internal-nacl-plugin",
        "version": ""
      },
      {
        "enabled": true,
        "name": "Chrome PDF Viewer",
        "path": "internal-pdf-viewer",
        "version": ""
      },
      {
        "enabled": true,
        "name": "Adobe Flash Player"
      },
  {
        "enabled": true,
        "name": "Chrome PDF Viewer"
      },
      {
        "enabled": true,
        "name": "Native Client"
      },
      {
        "enabled": true,
        "name": "Widevine Content Decryption Module"
      }
    ],
    "show_details": false
  },

En negrita están los 3 nodos del array "plugins_list" correspondientes al PDF Viewer. Si ponemos sus atributos "enabled" a false desde un script tendremos lo que queremos. Esto se hace también con jq, ya que sirve tanto para ver como para modificar ficheros JSON. Tras empollar varias docenas de ejemplos de uso de "jq", puedo aseverar que el código en cuestión es:
# CONFIG="$HOME/.config/google-chrome/Default/Preferences"
# cat $CONFIG | jq '.plugins.plugins_list |= map(if .name=="Chrome PDF Viewer" then .enabled=false else . end)'  | tr -d '\n' | tr -s " " > $CONFIG.new
Vayamos por partes:
  1. cat $CONFIG: vuelca el fichero en la salida estándar
  2. jq '.plugins.plugins_list |= map(if .name=="Chrome PDF Viewer" then .enabled=false else . end)': procesamos el fichero hasta dar con plugins.plugins_list, buscamos nodos cuyo name sea "Chrome PDF Viewer" y ponemos su campo enabled a false. El resto lo dejamos como está.
  3. tr -d '\n' | tr -s " " > $CONFIG.new: quitamos retornos de carro y espacios en blanco de la identación, ofuscando de nuevo el json. El resultado se guarda en la misma ruta, en Preferences.new
Una vez hecho esto, copiamos Preferences.new en Preferences y ya está hecho.

Pues no, tenemos otra mala noticia. Desgraciadamente me encontré con que hay muchas veces en que ".plugins" está vacio, aunque el PDF Viewer está activado, y el nodo plugins_list no aparece hasta que entramos manualmente en "about:config".

Ese caso hay que detectarlo e inyectar dentro del JSON una rama plugins_list con el enable=false allí donde corresponda. Eso se hace con este código (ojo, metemos el array plugins_list completo en una sola línea, es bastante largo):
salida=$(cat $CONFIG | jq '.plugins.plugins_list[0]')
if [ "$salida" = "null"  ]
then
   cat $CONFIG | jq '.plugins={ "show_details": true, "plugins_list": [ { "version": "", "path": "chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/", "name": "Chrome PDF Viewer", "enabled": false }, { "version": "23.0.0.162", "path": "/var/home/usuario/.config/google-chrome/PepperFlash/23.0.0.162/libpepflashplayer.so", "name": "Shockwave Flash", "enabled": true }, { "version": "1.4.8.824", "path": "/opt/google/chrome/libwidevinecdmadapter.so", "name": "Widevine Content Decryption Module", "enabled": true }, { "version": "", "path": "/opt/google/chrome/internal-nacl-plugin", "name": "Native Client", "enabled": true }, { "version": "", "path": "internal-pdf-viewer", "name": "Chrome PDF Viewer", "enabled": false }, { "name": "Adobe Flash Player", "enabled": true }, { "name": "Chrome PDF Viewer", "enabled": false }, { "name": "Native Client", "enabled": true }, { "name": "Widevine Content Decryption Module", "enabled": true } ], "last_internal_directory": "/opt/google/chrome"}' | tr -d '\n' | tr -s " " > $CONFIG.new
fi 
Ahora si plugins_list no existe o está vacío le metemos dentro la rama entera con los plugins, poniendo enabled=false en los Chrome PDF Viewer. Ahora sí funcionará. Como dicen en mi pueblo, "enjuntándolo todo" queda este script:
# cat google_disable_pdf_viewer 
#!/bin/bash

if [ "$1" = "" ]
then
  echo "Falta parametro con la ruta del home"
  exit 1
fi

if [ ! -e /usr/bin/jq ]
then
   echo "No hay jq, instalalo"
   exit 1
fi

CONFIG="$1/.config/google-chrome/Default/Preferences"

if [ ! -e $CONFIG ]
then
  echo "No existe $CONFIG"
  exit 1
fi

#Verificamos si existe la rama .plugins con contenido. Muchas veces esta vacia y no podemos poner a false el plugin.
salida=$(cat $CONFIG | jq '.plugins.plugins_list[0]')
if [ "$salida" = "null"  ]
then
   cat $CONFIG | jq '.plugins={ "show_details": true, "plugins_list": [ { "version": "", "path": "chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/", "name": "Chrome PDF Viewer", "enabled": false }, { "version": "23.0.0.162", "path": "/var/home/usuario/.config/google-chrome/PepperFlash/23.0.0.162/libpepflashplayer.so", "name": "Shockwave Flash", "enabled": true }, { "version": "1.4.8.824", "path": "/opt/google/chrome/libwidevinecdmadapter.so", "name": "Widevine Content Decryption Module", "enabled": true }, { "version": "", "path": "/opt/google/chrome/internal-nacl-plugin", "name": "Native Client", "enabled": true }, { "version": "", "path": "internal-pdf-viewer", "name": "Chrome PDF Viewer", "enabled": false }, { "name": "Adobe Flash Player", "enabled": true }, { "name": "Chrome PDF Viewer", "enabled": false }, { "name": "Native Client", "enabled": true }, { "name": "Widevine Content Decryption Module", "enabled": true } ], "last_internal_directory": "/opt/google/chrome"}' | tr -d '\n' | tr -s " " > $CONFIG.new
   if [ $? -eq 0 ]
   then
      cp -f "$CONFIG" "$CONFIG.bak2" 
      mv "$CONFIG.new" "$CONFIG"
   fi
else
   #Comprobamos si el plugin Chrome PDF Viewer está activdo, buscando enabled=true en alguna entrada del plugin. con los tr se "des-beautifica"
   salida=$(cat $CONFIG | jq '.plugins.plugins_list[] | select(.name=="Chrome PDF Viewer") | .enabled' 2> /dev/null | grep true)
   if [ "$salida" != "" ]
   then
      cat $CONFIG | jq '.plugins.plugins_list |= map(if .name=="Chrome PDF Viewer" then .enabled=false else . end)'  | tr -d '\n' | tr -s " " > $CONFIG.new
      if [ $? -eq 0 ]
      then
         cp -f "$CONFIG" "$CONFIG.bak2" 
         mv "$CONFIG.new" "$CONFIG"
      fi
   else
     echo "Ya está desactivada"
   fi
El script toma un parámetro, que sería el HOME del usuario al que queremos aplicar la desactivación del PDF Viewer de Chrome. Ya solo es cuestión de hacer un script que recorra los homes deseados y lo vaya haciendo. Incluso si ponemos el script en un crontab podemos hacerlo a diario para anular de un día para otro cualquier modificación que haga algún usuario por su cuenta.

Y ya está. Bastante mas doloroso en Chrome que en Firefox. Odio los programas que no tienen una configuración de opciones global y bloqueante. Me despido recordando que:





miércoles, 2 de noviembre de 2016

Desactivar el visualizador de PDF de Firefox - Poner configuración forzosa.

Una cosa que nos pasa con frecuencia es que los documentos bajados de Rayuela y mostrados con el visualizador de PDF embebido en Firefox aparecen con caracteres muy solapados y/o desaparecidos al mandarlos a impresión. También pasa con PDF de otros orígenes, pero en el caso de los de Rayuela no falla: imprimes y te sale un galimatías.

Al final, para ahorrarnos quebraderos de cabeza (ya que parece que la culpa de que Rayuela genere esos PDF que Firefox no digiere la tienes tú) compensa desactivar el visualizador embebido y que los PDF de abran con evince, adobe reader o la aplicación que corresponda. La forma manual de desactivarlo es abrir el navegador, poner "about:config" en la barra de direcciones, buscar "pdfjs.enabled" y ponerlo a false. Pero si tienes 500, 1000 o más cuentas de usuario no vas a hacerlo una a una.

La opción mas sencilla, que nos garantiza además que el usuario no pueda volver a activarlo es usar el fichero /etc/firefox/syspref.js, que permite meter configuraciones por defecto u obligatorias para todos los usuarios que inicien sesión en la máquina en cuestión. Este fichero ha ido cambiado de ubicación y nombre a lo largo de la historia de Firefox/Iceweasel. Esperemos que ya se quede para siempre ahí. Bueno, pues el contenido del fichero que pongo es:
# cat syspref.js
// Lock specific preferences in Firefox so that users cannot edit them
lockPref("app.update.enabled", false);
lockPref("browser.startup.homepage", "http://www.google.es");
lockPref("extensions.update.enabled", false);
lockPref("browser.shell.checkDefaultBrowser", false);
lockPref("extensions.blocklist.enabled", false);
lockPref("print.postscript.paper_size","A4");
//Proxy
lockPref("network.proxy.type",0);
// Use LANG environment variable to choose locale
lockPref("intl.locale.matchOS", true);
lockPref("pdfjs.disabled", true);
Como se puede observar, aprovecho para fijar otras cosas que me gusta tener controladas: página de inicio, tamaño de papel de impresión, etc. El "lockPref" nos asegura que el usuario tendrá bloqueado el cambio de esa opción de configuración. Si en su lugar ponemos "pref" la opción tendrá ese valor por defecto, pero cada usuario podrá cambiarla a su gusto a posteriori. Como además queremos aplicar este fichero en todas las máquinas nada mejor que una regla puppet para hacerlo, que sería:
# cat init.pp
class miclase {
....
   file {"/etc/firefox/syspref.js":
                   owner=>root, group=>root, mode=>644,
                   source=>"puppet:///modules/miclase/syspref.js",
    }
....
}
Bueno, pues con esto nos despreocuparemos de este tema para siempre... a no ser que usen Google Chrome.

lunes, 31 de octubre de 2016

Force brute attack a un lápiz de la pizarra Interwrite (Part Two)

Retomo un tema antiguo, ya tratado con anterioridad: el desmontaje de los lápices magnéticos de las pizarras Interwrite

Como los lápices siguen muriendo tengo suministro constante de ellos para experimentar, así que hace un par de semanas me decidí a diseccionar otro para confirmar o rebatir mis suposiciones del anterior artículo. Gracias al know-how de la anterior disección en esta ocasión la carnicería fue menos traumática para el lápiz.

Aquí vemos el corte realizado con una pequeña sierra de metal (con dientes minúsculos) para dejar a la vista la pila y el sistema de carga:



Ahora podemos ver como estaba yo equivocado en mi idea del cableado expuesta en el anterior post:




Cosas que quedan claras:
  • El polo positivo de la pila ya he comprobado con un multímetro que es el que apunta hacia abajo (ya que la pila está al revés de lo normal, con el polo negativo hacia arriba) y está conectado a terminal marcado + (más) en la placa del circuito impreso.
  • El polo negativo de la pila, el que está arriba, está conectado mediante un cable al a terminal marcado - (menos) en la placa del circuito impreso.
  • Los dos "brazos" de chapa que se usa para cargar el lápiz cuando está en la base no están directamente conectados a la pila. Están conectados al circuito impreso y desde allí cargarán la pila cuando reciban corriente de entrada.
Unas cuantas vistas más inferior y superior:





Por ultimo, fotos en HDR, para aprovechar que he descubierto que mi móvil tiene esto y saco fotos mucho mas claras con ello:



Bueno, con este lápiz parece mas sencillo poner una pila nueva, ya que no ha quedado tan destrozado. Estoy valorando probar a dar el cambiazo.

Una buena noticia es que Interwrite vende ahora unos modelos de lápices donde la pila es bastante mas fácil de intercambiar cuando llega al fin de su vida útil. Usan pilas recargables AAAA NiMh de 1.2V. Aquí una fotino y podemos ver que el lápiz se abre con una pestañita y sin que haga falta mutilar la carcasa:

Bueno, dije que intentaría volver antes de que hubiese presidente, pero no he podido cumplir mi promesa. Mal empezamos la legislatura.

viernes, 21 de octubre de 2016

Comandos útiles para gestionar los puntos de acceso wifi Dlink DIR-860L

Bueno, ya hemos hablado antes de nuestro DD-WRT embebido en los puntos de acceso Dlink. Conforme vamos trabajando con ellos y a sabiendas de que nos darán algún que otro quebradero de cabeza voy haciendo una lista de comandos interesantes.

Recordemos que accedemos a ellos por ssh, aunque tienen interfaz web y telnet (esta última normalmente desactivada por poco segura). Todos estos comandos están referidos a la red normal de 2.4Ghz. Si tenemos además activa la de 5Ghz habrá comandos equivalentes.

Levantar la red wifi manualmente para que se puedan conectar al punto de acceso:
# ifconfig ra0 up
Apagar la wifi:
# ifconfig ra0 down
Ver estado de la red wifi:
# cat /sys/class/net/ra0/operstate
Averiguar el SSID de la red wifi:
# nvram get wl0_ssid
Ver muchos parámetros de la red wifi:
# nvram show | grep wl0
La contraseña de acceso ssh se guarda en /etc/passwd, como cualquier Unix. Dicha contraseña se cambia con:
# setpasswd micontrasena
Luego, el interface web para acceder por navegador tiene su propio usuario de acceso que no tiene por que ser "root", pero en nuestro caso si lo es por mantener la homogeneidad en todos los centros. También tiene una contraseña que coincide con la de /etc/passwd. Ambos se establecen con:
# setuserpasswd usuario micontrasena
# nvram commit
Ojo, cuando ejecutamos setuserpasswd la contraseña de /etc/passwd también se cambia pasados unos instantes. Podemos consultar usuario y contraseña para el acceso web con:
# nvram get http_username
# nvram get http_passwd
Veremos que se almacenan ambos codificados con md5, con formatos del estilo "$1$.NhRDhhO$CB9/G3KJV8.cfUyQUMie3/".

Otra cosa que solemos hacer es activar el protocolo https y desactivar el protocolo http para llegar al punto de acceso. Desde linea de comandos haremos:
# nvram set http_enable=0
# nvram set https_enable=1
# nvram commit
Recordemos que "nvram commit" escribe los cambios en la memoria del punto de acceso para que se guarden de manera permanente.


Addenda 24 noviembre: mi compañero Chema me pasa otro comando interesante, para cambiar el canal de emisión de la wifi o dejarlo en automático (valor "0" en la asignación):
# nvram set wl_channel=7
# nvram set wl0_channel=7
# nvram commit

Otra cosa que hemos advertido en este router es que es bastante lerdo a veces a la hora de aplicar los cambios realizados y no viene mal hacer un:
# reboot
Para que se configure bien de acuerdo a nuestras órdenes.

Bueno, pues como dijo el T-800 al oficial de policía que no le permitía presentar sus respetos a Sarah Connor:


A ver si lo consigo antes de que haya gobierno, que estoy en ascuas por saber quien es el presidente.

miércoles, 5 de octubre de 2016

Modificar y reempaquetar un .deb

Recientemente he tenido algún problema con 2 paquetes que me daban quebraderos de cabeza a la hora de mantener la coherencia de mi sistema de paquetes Debian. Ya que tenemos un eX-presidente que piensa que se puede traspasar los límites del Estado de Derecho por el "bien común" (de unos pocos) he pensado que yo también puedo traspasar los límites de las reglas del sistema de paquetes para mantener la coherencia. Cada uno hace la puñeta hasta donde puede :-P.

Para uno de ellos había en repositorios una versión mayor y se actualizaba al hacerse pkgsync. Ni siquiera un hold funcionaba para hacer que se quedase quietecito. La solución pasaba por modificar el paquete original y cambiar internamente el número de versión, poniendo una mucho mas alta (de la 2.0.4 a la 2.9.9, por ejemplo) para asegurarnos que por mucho tiempo que pase no se va a machacar dicha versión en ninguna actualización.

Para el otro el problema era que tenía una dependencia que instalaba una aplicacioncilla de diseño de circuitos electrónicos que no era necesaria, pero esto provocaba una cascada de instalaciones que acababa chocando con las dependencias de otro paquete de terceros que si era imprescindible (el software de la pizarra Interwrite, concretamente). En este caso tenia que modificar las dependencias del paquete original y quitar lo que molestaba.

Si no tenemos el paquete que queremos modificar a mano podemos descargar el .deb de repositorios con:
# apt-get download mipaquete
Esto nos descarga mipaquete-xxx.deb. Ahora necesitamos desempaquetarlo para hurgar dentro. Para ello usamos dpkg-deb
# apt-get install dpkg
# mkdir trabajo
# dpkg-deb -R mipaquete-xxx.deb trabajo
Esto desmontará el paquete y lo quedará dentro de "trabajo" para que podamos retocarlo. Supongamos que hemos descargado el paquete arandr para modificarlo. Los datos a retocar para los casos que he expuesto antes están en:
# cat trabajo/DEBIAN/control
Package: arandr
Version: 0.1.9-1
Architecture: all
Maintainer: Ubuntu Developers 
Original-Maintainer: Christian M. Amsüss 
Installed-Size: 309
Depends: python (>= 2.7), python (<< 2.8), x11-xserver-utils | xrandr, python-gtk2
Section: x11
Priority: optional
Homepage: http://christian.amsuess.com/tools/arandr/
Description: Simple visual front end for XRandR
 ARandR is a visual front end for XRandR 1.2/1.3 (per display options), which
 provides full control over positioning, saving and loading to/from shell
 scripts and easy integration with other applications.
Modificando el apartado "Version" puedo poner la que yo quiera, modificando "Depends" puedo añadir o quitar dependencias. Una vez retocado a nuestro gusto tocra reempaquetar:
# dpkg-deb -b trabajo mipaquete-yyy.deb
Y se creará el fichero mipaquete-yyy.deb que podremos a instalar a mano con:
# dpkg -i mipaquete-yyy.deb; apt-get -f install
Y ya tenemos nuestro paquete tuneado para que no de problemas con lo que queramos hacer. Por supuesto no estamos circunscritos a trabajo/DEBIAN/control, también podemos retocar los scripts de pre y post-instalación, los mismos ficheros que componen el paquete y que se instalan por /usr/bin/ y demás ubicaciones. Incluso podemos crear un paquete desde cero así de una forma rápida, usando otro como plantilla.

Nos vemos cuando haya otras cosas interesantes que contar... o cuando tengamos Gobierno, lo que antes llegue.

sábado, 24 de septiembre de 2016

VirtualBoxing Windows (Parte II)

En la anterior entrada vimos como virtualizar Windows dentro de nuestros Xubuntu para satisfacer en nuestros Infolab las necesidades de todos, les haga falta Windows o no.

Con el sistema ya en despliegue tuve que hacer varias correciones menores que cuento aquí:

1. Cambios en la BIOS para que funcione VirtualBox.

Los PC usados son HP ProDesk 600 G2 SFF, que tienen Secure Boot activado en la BIOS por defecto. Los últimos kernel de Ubuntu están viniendo configurados para que si se detecta Secure Boot activado los drivers de terceros deban estar firmados para cargarlos en memoria. El driver de virtualbox es un problema aquí y firmarlo es un proceso complicado que habría que repetir con frecuencia con cada actualización.

La solución mas rápida es entrar con la tecla F10 en la BIOS durante el arranque, desactivar Secure Boot, borrando las claves del mismo y poniendo que el arranque sea solo en modo Legacy. Al guardar y reiniciar nos pedirá un código numérico a modo de CAPTCHA cutre para confirmar que lo hemos hecho a propósito y ya está. El driver de virtualbox podrá cargarse sin problema. Todo esto ya lo contamos en el apartado 2 de esta entrada.

También será necesario en la parte Avanzada de la BIOS activar el VTx para permitir la virtualización, ya que si no el virtualbox se queja al arrancar y aborta.

2. Cambios en el script de arranque.

Para poder arrancar la máquina virtual cpm un click del usuario, verificando que ya no había otra corriendo y mapear la carpeta $HOME del usuario dentro de la máquina virtual usábamos un script.

Tras varias pruebas apareció el problema de que la carpeta compartida se quedaba mapeada en la máquina virtual, lo cual daba problemas al cambiar de usuario. Con la línea en negrita que añado en el script se soluciona el problema: desmapeamos la carpeta compartida antes de mapearla de nuevo.
# cat /opt/VirtualBox\ VMs/run_vbox 
#!/bin/bash

#Poniendo esto  /etc/environment
#export VBOX_USER_HOME="/mnt/VirtualBox VMs/VirtualBox"
#en el arranque lo tendremos para todos los usuarios. Maquinas virtuales en local.

#Si cierran la ventana a lo bruto se hace un shutdown de la máquina. Esto al .vbox de 
#la máquina
#    

machine="Win10"

running=$(VBoxManage list runningvms | grep $machine)
if  [ -n "$running" ]
then
   zenity --error --text "La máquina $machine ya está funcionando"  
else
  #Si cierran la ventana a lo bruto se hace un shutdown de la máquina. Esto al .vbox de la máquina
  #    
  #o bien VBoxManage...
  VBoxManage setextradata $machine "GUI/LastCloseAction" "Shutdown"
  VBoxManage sharedfolder remove "$machine" --name "compartido"
  VBoxManage sharedfolder add "$machine" --name "compartido" --hostpath "$HOME" --automount
  VirtualBox --startvm $machine
fi

3. Problemas de permisos.

Como la máquina virtual completa es compartida por todos los usuarios y está en una carpeta común (/opt/VirtualBox VMs) hay varios ficheros que deben tener como propietario al usuario actual, para que pueda ejecutarla sin problema.

Para ello hace falta meter un script que se ejecute en el inicio de sesión y que lo haga como root (hay que cambiar permisos a unos ficheros de los que no somos propietarios). Está ultima condición descarta el uso de /etc/xdg/autostart/* y /etc/X11/Xsession.d/*. Para ejecutar un script en el inicio de sesión como root tenemos que usar la configuración de ligthdm, nuestro gestor de sesiones, metiendo un fichero en /etc/lightdm/lightdm.conf.d/ como.
# cat /etc/lightdm/lightdm.conf.d/15-vbox.conf 
[SeatDefaults]
# Seat defaults
# display-setup-script = Script to run when starting a greeter session (runs as root)
# greeter-setup-script = Script to run when starting a greeter (runs as root)
# session-setup-script = Script to run when starting a user session (runs as root)
# session-cleanup-script = Script to run when quitting a user session (runs as root)
session-setup-script=/opt/VirtualBox\ VMs/vbox_permisos
El script llamado es vbox_permisos, que hace:
# cat vbox_permisos 
#!/bin/bash
#Cambia el propietario de las ficheros de VirtualBox, para permitir el acceso al usuario que hace login
chown $USER:$USER "/opt/VirtualBox VMs/VirtualBox/VirtualBox.xml"
chown $USER:$USER "/opt/VirtualBox VMs/Win10/Win10.vbox"
Como se puede ve, hace se propietario al usuario que inicia sesión de "/opt/VirtualBox VMs/VirtualBox/VirtualBox.xml" y "/opt/VirtualBox VMs/Win10/Win10.vbox", que son los dos ficheros necesarios para arrancar la máquina virtual.

Con esto ya está todo solucionado y funciona sin problemas.... de momento.

Por último, recordemos la conveniencia de tener una copia de estos 2 últimos ficheros, los scripts y el fichero .vdi con la máquina virtual en lugar seguro de la máquina física, para hacer una restauración rápida si algún usuario avanzado de Windows nos desconfigura o borra algo.