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

sábado, 31 de diciembre de 2016

Hasta los uefis

Voy a echar un poco de bilis, ya que llevo varios meses teniendo encontronazos con este tema y tengo que escribir sobre ello. Antes de nada debo dejar constancia que no domino el asunto y que seguramente estoy equivocado y confundo conceptos, pero soy español (y cuñado) y eso me faculta para sentar cátedra, sepa o no.

Hace muchos años, cuando era mas bisoño me creía casi cualquier cosa que sonase chachi y bien. Por ejemplo, pensaba que el dinero de los bancos centrales estaba respaldado por oro y otros bienes tangibles en cajas fuertes rodeadas de guardias armados y que cuando se "emitía moneda" era porque se había se comprado oro para respaldar esa emisión y estaba en esta forma:



Juas, juas, era mas inocente que Bambi. El dinero se crea desde hace decenios con un spinner



Tras esta ida de olla recupero el hilo y, como decía, en esos años recuerdo haber leído un prometedor artículo sobre la nueva generación de BIOS que venía a mejorarnos las cosas sin que nadie la hubiese pedido, como tantas y tantas cosas que el capitalismo nos regala y luego nos cobra con intereses.

Era tremendo: unas BIOS amigables con entorno gráfico que nos permitrían conectarnos a Internet y navegar, ejecutar utilidades y realizar reparaciones (e instalaciones) del sistema operativo en un PC que lo tuviese dañado. Un sistema embebido que nos traería al futuro. Un futuro glorioso.

Bueno, como dice la Polla Records, hoy es el futuro. Esa BIOS se llamo EFI y luego UEFI. Repasemos rápido las prestaciones: soporta particiones GPT, admite drivers y aplicaciones ad-hoc para cargar y ejecutar desde la BIOS, tiene un en entorno modular, un gestor de arranque y un GUI manejable con ratón,.... Repasemos cada "avance":

  • Particiones GPT, adios al MBR. Ya podemos tener mas de 4 particiones por disco duro, ¡Gloria a Adonai!. Bueno, maticemos . Ya habia otros métodos usados en BIOS para tener mas de 4 particiones. Eso no dependía realmente de la BIOS, sino de la estructura de datos de 4 registros usada como tabla de particiones de tipo msdos en los 512 bytes del MBR (o mas si teníamos un gestor de arranque mas elaborado que el básico).
  • Un sistema para cargar drivers hechos especialmente para EFI y tener un entorno con red, sonido, rayos láser y conexión con la cafetera USB. Una vieja demanda de los usuarios: una BIOS con drivers para dispositivos complejos.
  • Podemos usar el ratón en un entorno gráfico chachi. Yo he visto varias BIOS de AMI manejadas con ratón en un modo gráfico algo vintage, pero mejor que no se corra la voz, que luego soy un aguafiestas.
  • Abundando en el entorno UEFI: la U significa "Universal", pero desde luego el GUI no es universal. Cada máquina y modelo tiene una UEFI con sus propios menús y hotkeys según la distribución aleatoria que escoge mediante dados el encargado del desarrollo.
  • Un gestor de arranque propio, vaya, debe ser que el Grub y la pléyade de gestores de arranque que hay no les parecia bastante.
  • También recuerdo que a mi me prometieron hace años que se podría conectar remotamente a la BIOS y reinstalar un sistema operativo dañado desde ella, pero que yo sepa eso solo lo he visto implementado en servidores con algo que, a diferencia de UEFI, si es útil y funciona bien: los sistemas de gestión out-of-band, como el ILO de HP y el equivalente de otras marcas, que llegan de verdad a donde EFI se quedó en promesa.
  • No solo eso, resulta que me comenta mi compañero Oscar que además se pude instalar un backdoor en el UEFI y comunicarnos con él desde el sistema operativo, de tal manera que se podrán escalar privilegios hasta ser usuario root. Como dicen en el artículo enlazado: "And, more importantly, once your kernel was loaded, BIOS was pretty much out of the picture"/"una vez el kernel se ha cargado, la BIOS está mas bonita fuera de escena".


Pero bueno, yo he venido aquí a hablar de mi libro, y realmente lo que me revienta de UEFI son las aplicaciones.La E de UEFI significa extensible, y yo entiendo que eso significa que se puede extender con aplicaciones. Veamos la lista de aplicaciones, ese prometedor "UEFI app store":


Todo lo que he podido encontrar son frikadas, ejemplos del nivel de un "Hello World" y cosas rarunas. Lo anuncio con el corazón encogido: nunca podremos navegar en Internet desde nuestra EFI.

Y ahora es el momento de contar de que va el post. Yo sé para que existe EFI, por que se ha implementado y por que perdurará: la respuesta es Secure Boot. Ese engendro concebido para impedir o dificultar al máximo la instalación de sistemas operativos que no sean de Microsoft. Estoy seguro de que UEFI existe, está concebida e impulsada para implementar Secure Boot. Todo lo demás es una cortina de humo que se puede implementar de forma mucho menos barroca desde un bootloader o con un sistema out-of-band.

Y Secure Boot no es un sistema para impedir que entre malware, no seamos niñatos. La mayoria de malware que veo se mueve en pendrives y se ejecuta con rol de usuario, buscando un sistema donde pueda escalar a administrador. ¿Que porcentaje del malware existente intenta modificar el arranque?. Por favor, que no estamos en los 80 con el virus Stoned. Todo es mentira. La única finalidad es hacer la puñeta y lo consiguen.

Hace un tiempo he perdido varias horas en un PC con una tarjeta gráfica nvidia que al cerrar sesión o intentar ir a consola quedaba el entorno gráfico "colgado", sin errores en los logs y el PC accesible por ssh, aunque las X eran imposibles de matar y un kill -9 era ignorado. Si en UEFI habilito Secure Boot eso no pasa. Si deshabilito Secure Boot y dejo el arranque Legacy, si pasa. ¿Que conexión hay entre Secure Boot y el comportamiento de una tarjeta nvidia?. Ni lo se ni me importa.

Me reafirmo: Secure Boot está concebido para hacer el mal y lo hace muy bien.

Feliz entrada de año.

miércoles, 21 de diciembre de 2016

Sobreescribir una regla puppet

Estaba escribiendo una regla puppet que necesitaba para instalar un paquete de mi compañero Esteban Navas de forma local y me he encontrado que ya hay otra regla puppet puesta por la Sección que choca con la mía:
package { "pkgsync": 
        ensure => latest 
}
Evidentemente, no puedo borrar la regla puppet de la Sección ya que su puppetmaster reina y tiraniza el mío, lo cual es lo correcto. Pero he descubierto que si puedo sobreescribirla/anularla ("override") para que ignore la suya y tenga en cuenta la mía, en una suerte de disidencia limitada. Es un concepto parecido al overriding de métodos en POO al definir una clase que hereda de otra.

Mi idea era poner esto:
package { "pkgsync" :
                  provider => dpkg,
                  ensure => latest,
                  source => "/var/cache/pkgsync_1.35-1_all.deb",
                  configfiles => replace,
}
Pero claro, me da un conflicto con lo anterior y el puppet peta a lo grande. En cambio si lo pongo con esta curiosa sintaxis:
Package  <|title == "pkgsync"|> {
                  provider => dpkg,
                  ensure => latest,
                  source => "/var/cache/pkgsync_1.35-1_all.deb",
                  configfiles => replace,
}
El puppet lo acepta, ignora lo de la Sección y coge mi regla. Estupendo.

Bueno nos vamos pero no sin compartir la noticia de la semana-mes-año-siglo: el EMDrive parece que funciona, según las pruebas que han hecho los chinos en su estación espacial. Es poco probable que sea cierto, pero como funcione me voy a dar un viaje a Marte, sin que me frían las neuronas como a Arnie, y una vez alli que me busque Rita:





Descarga directa de linea de comandos desde Google Drive

Últimamente me veo en la tesitura de descargar ficheros bastante grandes (vídeos e imágenes de clonación, por ejemplo) que me pasan vía enlaces de Google Drive. Aunque la descarga se puede hacer desde el navegador a veces esto no es lo mas cómodo, ya que:
  • Por algún motivo inexplicable, estas descargas desde el navegador son mas delicadas y no es extraño que fallen. Concretamente, cuando van al 95%.
  • Si el destino del fichero es otro PC (por ejemplo, un servidor sin entorno gráfico y navegador) luego hay que copiar el fichero desde nuestro PC al destinatario.
  • Somos sysadmin, si algo se puede hacer por consola es una pérdida de tiempo andar moviendo el ratón.
Por tanto partimos de un enlace a un fichero almacenado de Google Drive (y compartido de forma pública) como éste:
https://drive.google.com/open?id=0B8np4HndYC-lQi0wamstRHF1S3M
Y queremos descargarlo como se descargan ficheros con wget o curl. Evidentemente, usar wget o curl con este enlace no funciona. Necesitamos otra herramienta llamada gdrive. En su página viene un completo manual ya que es una herramienta muy potente para interactuar de muchas formas con Google Drive desde línea de comandos, aunque a mi solo me interesa de momento descargar ficheros.

Lo primero es bajar el programa, que es un ejecutable tal cual sin empaquetar. Las versiones para Linux usables por nosotros son:
  • gdrive-linux-x64 2.1.0 Linux 64-bit 4fd8391b300cac45963e53da44dcfe68da08d843
  • gdrive-linux-386 2.1.0 Linux 32-bit de9f49565fc62552fe862f08f84694ab4653adc2
Bajamos la que corresponda según nuestra arquitectura, la hacemos ejecutable con chmod +x y la ponemos en /usr/local/bin o ruta similar. Una vez descargado debemos lanzar una ejecución inicial para activar la conexión de la aplicación con nuestra cuenta de Google Drive:
$ gdrive-linux-x64 about
Authentication needed
Go to the following url in your browser:
https://accounts.google.com/o/oauth2/auth?access_type=offline&client_id=367116223233053-7n0vf5akeru7on6o2fjinrareaccpdoe99eg.apps.googleusercontent.com&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3A33qb&response_type=code&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive&state=state
¿Qué es esto?, pues una URL que hay que pegar en el navegador web, tras esto nos pedirán las credenciales de nuestra cuenta Gmail y mostrará esta pantalla:


Pinchando sobre "Permitir" nos dará el código de validación:
Copia este código, ve a tu aplicación y pégalo en ella:
4/Pvl90areaertc323a8acedTee9Jgoc
Copiando el código "4/Pvl90areaertc323a8acedTee9Jgoc" o el que nos salga, nos vamos al terminal desde donde hicimos "gdrive-linux-x65 about" y lo pegamos:
Enter verification code: 4/Pvl90areaertc323a8acedTee9Jgoc
Nos contestará con:
User: Tu nombre, tu.cuenta@gmail.com
Used: 6.0 GB
Free: 10.1 GB
Total: 16.1 GB
Max upload size: 5.2 TB
Una vez hecho esto ya tenemos la cuenta autenticada en gdrive (se ha creado un fichero en ~/.gdrive/token_v2.json, ojo con su custodia porque da acceso a nuestro Google Drive) y ya podemos lanzar la descarga usando el id del fichero en cuestión:
# gdrive-linux-x64 download 0B8np4HndYC-lQi0wamstRHF1S3M
Si es un fichero de varios Gigas y va a llevar horas es aconsejable usar screen como conté aquí.
Y nada mas, descarguen mientras sea gratis.

sábado, 17 de diciembre de 2016

Funciones puppet para añadir líneas a ficheros

Dado que gestionamos gran número de equipos mediante puppet, todo lo que sea automatizar y ampliar las funcionalidades del mismo nos viene bien. Ya mostré aquí un par funciones puppet para facilitar la descarga e instalación paquetes .deb en nuestros clientes, muy útiles cuando tratamos con paquetes sueltos fuera de repositorios que no podemos gestionar mediante el recurso puppet package.

En esta sentido son muy interesantes estos defines para gestionar ficheros de texto: permiten, entre otras cosas, añadir o borrar líneas de los mismos. Mi compañero Esteban los ha mejorado mucho, como podemos ver en su blog.

Por mi parte, y basándome en lo anterior he programado varias funciones más. La primera permite añadir una línea por encima de otra identificada por un patrón:
# cat /etc/puppet/defines/add_line_above.pp
#Añade la linea "line" al fichero "file", siempre que la cadena "search" no esté en el fichero.
#La línea la añade inmediatamente por encima de la línea que contenga la cadena "above".
#Usado por ejemplo para añadir lineas a /etc/rc.local por encima del "exit 0" con el cual
#siempre finaliza dicho script.

define add_line_above($file, $line, $search, $above) {
    exec { "/bin/sed -i --follow-symlinks '/${above}/i\\${line}' '${file}' ":
           unless => "/bin/grep -q '${search}' '${file}'"
    }
}
La segunda permite añadir una línea por debajo de otra identificada por un patrón:
# cat /etc/puppet/defines/add_line_below.pp
#Añade la linea "line" al fichero "file", siempre que la cadena "search" no esté en el fichero.
#La línea la añade inmediatamente por debajo de la línea que contenga la cadena "below". 
#En resumen: añade lineas al script por debajo de una linea dada, siempre y cuando no encuentre
# un patrón en el fichero. 
define add_line_below($file, $line, $search, $below) {
    exec { "/bin/sed -i --follow-symlinks '/${below}/a ${line}' '${file}' ":
           unless => "/bin/grep -q '${search}' '${file}'"
    }
}
La tercera permite añadir una línea en una posicion concreta dentro del fichero.
# cat /etc/puppet/defines/add_line_number.pp
#Añade la linea "line" al fichero "file", siempre que la cadena "search" no esté en el fichero.
#La ubica justo despues de la línea "pos" del fichero, quedando en la linea "pos+1" y desplazando
#las posteriores hacia abajo.

define add_line_number($file, $line, $search, $pos) {
    exec { "/bin/sed -i --follow-symlinks '${pos} a ${line}' '${file}' ":
           unless => "/bin/grep -q '${search}' '${file}'"
    }
}
Comentarios:
  • Estos ficheros .pp se guardarán /etc/puppet/defines/... del servidor puppet.
  • Dentro de nuestras clases haremos al comienzo import "/etc/puppet/defines/*.pp" para poder usarlos.
  • El --follow-symlinks del sed sirve para que si el fichero es un enlace simbólico que apunta a un fichero real ubicado en otro lugar, los cambios se hagan sobre el fichero real. Si no se especifica sed crea un nuevo fichero distinto del fichero real, que permanece inalterado.
  • En los tres casos file es el fichero donde buscar, line es la línea a insertar y search es la cadena a buscar para determinar si se inserta o no lo la línea.
  • El cuarto parámetro depende de la funcion.
Ejemplos de uso:
import "/etc/puppet/defines/*.pp"
class .... {

 #============================================================================================================================
 #Anade a rc.local (si no esta ya) el codigo que desactiva en el arranque la tarjeta de audio HDMI de la tarjeta grafica
 #lo hace justo antes de la linea exit 0.

 add_line_above { desactiva_audio_hdmi_siatic:
              file=> "/etc/rc.local",
              line=> 'bus=$(lspci | grep "Audio device: NVIDIA Corporation" | cut -d" " -f1) ; test -n $bus && echo 1 > "/sys/bus/pci/devices/0000:$bus/remove"',
              search=> "NVIDIA Corporation",
              above=> "^exit 0$"
 }

 #============================================================================================================================
 #Anade a etckeeper-commit-post (si no esta ya) una llamada al script /usr/bin/puppet_post_send
 #lo hace justo después la linea que contiene PATH.

 add_line_below { run_post_puppet:
              file=> "/etc/puppet/etckeeper-commit-post",
              line=> '/usr/bin/puppet_post_send',
              search=> "/usr/bin/puppet_post_send",
              below=> "PATH"
 }
}
Nos despedimos con un consejo del Estado:

miércoles, 14 de diciembre de 2016

Unetbootin muestra la ventana "en blanco" en Ubuntu Xenial

Los DEP Vexia Core que nos ha proporcionado la Consejería como herramienta de trabajo vienen equipados con un Ubuntu Xenial 16.04 que trae un escritorio Gnome3, que quiere ser versátil y parecido a un entorno de tablet pero es un poco endiablado y raro de manejar para la gente sencilla como nosotros.

Una de las cosas que hago continuamente es generar pendrives de arranque con distintos sistemas usando unetbootin. El problema que tengo con el Vexia es que al abrir unetbootin me aparecía esto:


Lo cual es bastante desalentador ya que no hay botones ni nada... Ejecutado desde terminal nos regala con estos mensajes de error:
# unetbootin
X Error: BadAccess (attempt to access private resource denied) 10
  Extension:    130 (MIT-SHM)
  Minor opcode: 1 (X_ShmAttach)
  Resource id:  0x13e
X Error: BadShmSeg (invalid shared segment parameter) 128
  Extension:    130 (MIT-SHM)
  Minor opcode: 5 (X_ShmCreatePixmap)
  Resource id:  0xf4
.............
.............
Buscando en foros de Arch y de ahi a Raspberry Pi apareció la solución: al parecer hay algun problema en libqt4 con determinados escritorios. El truco es teclear:
# export QT_X11_NO_MITSHM=1
# unetbootin
Con eso ya nos aparece de forma normal y podemos cargar imágenes y seguir trabajando. Os recuero que hay que trabajar para pagar la deuda de las autopistas rescatadas por el Gobierno en nuestro nombre. Ya os dije que estábamos mejor sin Gobierno, pero no me hicistéis caso.

domingo, 11 de diciembre de 2016

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

Aquí seguimos, dando guerra con los lápices Interwrite. Tras desmontarlo en la primera y segunda parte tenía pendiente intentar probar a cambiar la batería comprando una como ésta:


En mi tienda de componentes electrónicos favorita encontré por unos 2 neomarcos (aka euros) una pila que parecía la correcta. Estas son las fotos del cartonaje:


Cuando llegó vimos que, como diría Pepiño Blanco, "tenemos un problema de dificultades": la pila era un pelín mas larga que las pilas originales de lápiz, debe ser que el tamaño 1/3AAA no es siempre igual. Teniendo en cuenta que en nuestro caso el tamaño si importa esto podría traernos alguna dificultad para encajarlo bien. Como contrapartida positiva la pila nueva tiene 250mAh en lugar de 170mAh, lo que implica mas autonomía.

Esta vez cogí otro lápiz (recordemos que tengo lápices con la pila mal para aburrir), quité el tapón superior tirando sin miramientos con un alicate y con un cutter hice una incisión de neurocirujano, abriendo el hueco exacto para sacar la pila antigua y meter la nueva (no olvidemos que la polaridad debe respetarse, mirar el segundo artículo de la serie).

Aquí se ve todo ya colocadito:


Varias fotos con mas detalle y comento varias cosas importantes:

  • Se aprecia bien el tamaño un poco mayor de la pila nueva (esto nos impedirá poner el tapón luego).
  • A la hora de elegir el trozo de carcasa a cortar hay que pensarlo con cuidado: no deben tocar las dos lengüetas exteriores (las que hacen contacto en la base de carga) ni tampoco el cable interno que lleva al polo negativo de la pila. Mirar las fotos con cuidado para saber exactamente que porción he cortado para minimizar los daños.
  • Para sacar la pila vieja hay que actuar con cuidado y a la vez con firmeza (yo usé un destornillador plano de precisión y unas pinzas, para despegar las lengüetas superior e inferior), dejando los cables y las chapitas en su sitio de tal forma que evitaremos tener que soldar la pila nueva en un espacio tan exiguo.

Foto mas cercana:


Aquí se aprecia mejor la parte cortada de la carcasa, miremos como he respetado las dos lengüentas de carga y el cable de carga del polo negativo que va por dentro de la carcasa, eso nos deja libre una porción del círculo muy concreta para cortar:


Otro punto de vista:


Una vez metida la pila nueva, juntamos las lengüetas bien (aclaro para evitar malentendidos: me refiero a las lengüetas que van a los polos negativo y positivo de la pila, no a las lengüetas de carga de la carcasa) para que hagan contacto (yo no me atreví a soldarlas, alguien mas mañoso seguramente lo hubiera hecho) y cerramos todo con cinta aislante negra bien apretadita y tirante.



Queda poner algo para tapar la parte superior, ya que el tapón no nos entra debido al tamaño de la pila nueva. Seguramente la taparé con cinta dejando libres las lengüetas de carga para que hagan contacto con la base.

Bueno, pero...¿funciona?. Si, funciona. Dejé el lápiz cargando una noche en su base (el led de carga se enciende nada mas ponerlo, buena señal) y al día siguiente lo probé sobre una pizarra. Funcionaba sin problema. Por 2 euros y un rato de bricolaje tengo un lápiz funcional para varios años.

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.

Addenda 21-Noviembre-2017. Ayer desmonté otro lápiz (recordemos que tengo un montón de ellos averiados) y como cada vez hago menos destrozo saqué varias fotos. Las subo aquí para dar testimonio: