"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:



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.

miércoles, 21 de septiembre de 2016

Depurar errores de importación en controlies

Estamos a principios de curso y nuestro controlies echa humo con la importación de alumnos y profesores desde Rayuela. Antes de seguir, unos consejos para refrescar lo importante:
  • Controlies sólo importa ficheros de profesores y de alumnos. No de grupos, ya que esos datos van implícitamente dentro de los alumnos. El fichero XML de Grupos bajado de Rayuela no tiene ningún valor para controlies.
  • El formulario para importar los datos es el mismo tanto profesores como para alumnos...¿cómo distingue entre unos y otros?: pues por la extensión: si el fichero es un XML interpreta que es de profesores, si es un ZIP (que contiene un XML y las fotos) se interpreta que es de alumnos.
  • La casilla de "Borrar datos" solo debe marcarse en la primera importación del curso (normalmente hay varias importaciones a lo largo del año ya que las matriculaciones se realizan en varias oleadas) ya que borra todos los profesores/alumnos (según el caso) previos del árbol ldap antes de iniciar el proceso a modo de limpieza de datos obsoletos.
  • Si no se marca la casilla "Borrar datos" se integrarán los datos importados con los ya existentes previamente, siendo ignorados los profesores/alumnos que ya estuvieran en ldap. Por eso es aconsejable marcar la casilla al menos una vez con los alumnos y así deshacernos de aquellos que hayan abandonado el centro.
  • No hay que olvidar lanzar después el script crearCarpetas en el servidor principal para crear los homes Linux de los usuarios añadidos a ldap.

Cuando se realiza la importación no es infrecuente que se aborte con un "Internal server error" o similar. Veamos como solucionar esto o al menos saber que ha pasado:
  • Debemos asegurarnos de que no hay ninguna partición al 100% en el servidor principal. La importación se hace descomprimiendo datos en /tmp/rayuela-ldap y si la partición que contiene esta ruta se llena todo se va al traste.
  • Borrar /tmp/rayuela-ldap antes de importar tampoco viene mal, para liberar espacio y quitar "basura" de importaciones antiguas que pudieron quedar a medias.
  • Si sigue fallando hay que depurar, para ello borramos /var/web2py/applications/controlies/errors/* y lanzamos la importación para que se produzca de nuevo el error. En /var/web2py/applications/controlies/errors/... debería haberse creado un fichero con el volcado del error y en /tmp/rayuela-ldap deben estar además los ficheros temporales usados durante la importación.

El fichero en /var/web2py/applications/controlies/errors/... es un típico fichero de volcado de pila de web2py horrible y farragoso:
(dp1
S'output'
p2
S" 'ascii' codec can't encode character u'\\xe2' in position 2: ordinal not in range(128)"
p3
sS'layer'
p4
S'/var/web2py/applications/init/controllers/gestion.py'
p5
sS'code'
p6
S'# coding: utf8\nfrom applications.controlies.modules.Hosts import Hosts\nfrom applications.controlies.modules.Rayuela2Ldap import Rayuela  \nfrom applications.controlies.modules.SQLiteConnection import SQLiteConnection\nfrom applications.controlies.modules.Laptops import Laptops\nfrom applications.controlies.modules.LaptopsHistory import LaptopsHistory\nfrom applications.controlies.modules.Config import Config\nfrom applications.controlies.modules.Thinclients import Thinclients\nfrom applications.controlies.modules.Utils import Utils\nfrom applications.controlies.modules.Utils import LdapUtils\nimpo
......
......
......
S"u'Jo\\xe2o'"
p7197
sS'resultado'
p7198
S"u'Jo\\xe2o'"
p7199
sS'self'
p7200
S''
p7201
sssS'traceback'
p7202
S'Traceback (most recent call last):\n  File "/usr/lib/pymodules/python2.7/gluon/restricted.py", line 205, in restricted\n    exec ccode in environment\n  File "/var/web2py/applications/init/controllers/gestion.py", line 748, in \n  File "/usr/lib/pymodules/python2.7/gluon/globals.py", line 173, in \n    self._caller = lambda f: f()\n  File "/usr/lib/pymodules/python2.7/gluon/tools.py", line 2575, in f\n    return action(*a, **b)\n  File "/var/web2py/applications/init/controllers/gestion.py", line 218, in rayuela\n    todos=rayuela.gestiona_archivo()\n  File "applications/controlies/modules/Rayuela2Ldap.py", line 437, in gestiona_archivo\n
self.parsea_archivo("/tmp/rayuela-ldap/Alumnos.xml","alumno")\n  File "applications/controlies/modules/Rayuela2Ldap.py", line 249, in parsea_archivo\n    self.parse_nodo(nodo)\n  File "applications/controlies/modules/Rayuela2Ldap.py", line 236, in parse_nodo\n    usuario[info.nodeName]=self.asegura_codigos(dato)\n  File "applications/controlies/modules/Rayuela2Ldap.py", line 121, in asegura_codigos\n    return str(resultado).strip()\
nUnicodeEncodeError: \'ascii\' codec can\'t encode character u\'\\xe2\' in position 2: ordinal not in range(128)\n'
p7203
s.
La parte final es la interesante, he puesto en negrita lo relevante: se produce un error en /tmp/rayuela-ldap/Alumnos.xml, relacionado con la codificación Unicode de la cadena que aparece mas arriba S"u'Jo\\xe2o'. Habría que buscar esa cadena en Alumnos.xml por ver si viene en alguna codificación extraña y arreglarlo mano. Esto pasa a veces ya que los datos vienen desde Rayuela con codificaciones o caracteres extraños que controlies no sabe manejar.

Si no encontramos nada queda una última opción: seguir una estrategia "divide y vencerás" y realizar la importación grupo a grupo, en lugar de todo el alumnado completo, hasta dar con el que produce el error. Luego, dentro de ese grupo, hacerlo alumna a alumno hasta pillar al "culpable" y depurar.

Una vez localizado el dato erróneo será cuestión de editar el XML a mano para quitar lo que causa el fallo y lanzar de nuevo la importación. Si es el fichero de Alumnos no olvidar volver a meter Alumnos.xml dentro del ZIP para importar, respetando la estructura del ZIP original: el fichero Alumnos.xml en la raíz del mismo y las fotos en un directorio.

Bueno, pues esperemos que este año no haya muchos errores en estas lides.

lunes, 19 de septiembre de 2016

Configurando la VGA en los HP ProDesk 600 G2 SFF (Parte II)

Bueno, bueno, volvemos del verano con las uñas afiladas y muchas cosas en el tintero. Vamos a ampliar un post antiguo sobre los Infolab.

1. Usar driver propietario nvidia desde un repositorio PPA.

En la Parte I miramos como configurar la VGA de nuestro HP ProDesk en distintos escenarios. Recordemos que teníamos 2 tarjetas VGA
00:02.0 8086:1912 VGA compatible controller: Intel Corporation Sky Lake Integrated Graphics (rev 06) 
01:00.0 10de:1287 VGA compatible controller: NVIDIA Corporation GK208 [GeForce GT 730] (rev a1)  
Y que la nvidia la configurabamos con el driver propietario oficial de nVidia. Como este driver se instalaba mediante un fichero NVIDIA-Linux-x86_64-361.28.run y con varias preguntas de forma interactiva, era un proceso bastante poco operativo para hacer un despliegue masivo por muchas máquinas. Mis compañeros sugirieron otra forma que yo no había advertido para instalar el driver: mediante un repositorio PPA de Ubuntu que se actualice con los drivers propietarios nVidia. Para ello añadimos el repositorio:
# add-apt-repository ppa:graphics-drivers/ppa
# apt-get update
Y ahora el paquete con el driver:
# apt-get install nvidia-364
Hay varios paquetes que se informa que han funcionado: nvidia-361, nvidia-364 y nvidia-367. Pongo nvidia-364 porque al parecer es el que más compañeros han usado. Y ya está, de esta forma conseguimos tener el driver propietario de las nVidia sin tener que descargar el .run y ejecutarlo a mano. El resto del artículo anterior se mantendría igual.

2. Evitar problemas entre el Secure Boot de la BIOS UEFI y los drivers de terceros.

Otro problema que se nos puede presentar es que no se cargue el driver en el arranque. Es decir que:
# lsmod | grep -i nvidia
No muestre nada. Si intentamos cagarlo a mano:
# modprobe nvidia
Nos contestará con algo asi como "Required key not available" La causa de se explica en este enlace: básicamente consiste en que el kernel tiene activada una opción por la cual si encuentra en la BIOS UEFI el Secure Boot activado solo permitirá cargar drivers de terceros firmados previamente. Firmar drivers es un proceso bastante farragoso que habrá que repetir cada vez que se actualice el driver o el kernel.

Es mas sencillo para nuestro caso desactivar el Secure Boot, aunque implique ir por los PC uno a uno ya que no se puede automatizar. En caso el de los HP Prodesk 600 G2 pulsaremos F10 al arrancar en el equipo para entrar en la BIOS UEFI, iremos a Opciones Avanzadas/Seguridad y una vez allí desactivamos en el combo que sale el arranque Seguro UEFI, dejando solo el Legacy activado, y borramos las claves Secure Boot marcando la casilla. Una vez hecho esto guardamos y salimos de la BIOS.

En el siguiente arranque pide teclear a mano un úmero aleatorio de 4 digitos para confirmar que se quiere desactivar el arranque seguro, una vez hecho ya vuelve a cargar el driver nvidia y el problema desaparece. De igual manera que con el driver de la nvidia, esto soluciona problemas con otros drivers de terceros tales como:

-El driver de audio de este post.
-El driver nw_fermi de las pizarras Smart.
-El driver de VirtualBox.
-Etc, etc, etc.

Nos vemos pronto y ten por seguro que seguiremos sin Gobierno.

martes, 9 de agosto de 2016

A vueltas con el software de las PDI

Desde que empezaron a llegar pizarras digitales interactivas a los centros educativos hemos visto pasar ante nuestros ojos dispositivos de Interwrite, SmartBoard, Promethean, eBeam, Hitachi, Galneo y seguro que alguna artesanal hecha con el mando de la Wii. En algunos casos como Smart y Galneo la distribución ha sido masiva por todos los centros. En otros se han ido adquiriendo de forma esporádica o han llegado como premios por proyectos presentados por la comunidad educativa.

Cada una de estas pizarras tiene su propio software de manejo: Workspace para las Interwrite, SmartNotebook para las SmartBoard, Pandectas para las Galneo....Eso en principio no supone problema si vamos a usar la pizarra de la misma forma que una pizarra tradicional: un panel para escribir y borrar.

El problema viene cuando queremos sacar partido a lo que tenemos: guardar el trabajo para retomarlo más adelante, diseñar actividades interactivas, reutilizar las actividades realizadas por otros,.... En una jungla de distintos programas según la pizarra no hay manera de garantizar la reutilización de los contenidos. Como además se suelen guardar en formatos propietarios es casi imposible contar con herramientas de importación. Para mas INRI, el cambio de software de un aula y de un centro a otro acaba desalentando enormemente a los docentes que quieren introducirse en el uso de las PDI.

Creo que la única solución puede ser adoptar de forma oficial un software determinado que sea multiplataforma y que pueda usarse independientemente del hardware subyacente de la pizarra. A fin de cuentas es lo mas lógico, ¿no?: los programas que usamos para escribir manuales para imprimir, escanear documentos o grabar CD son independientes del dispositivo físico usado luego. ¿Por qué no habría de ser así en las PDI?.

En principio el Smart Notebook parece un buen candidato
, ya que se puede licenciar su para uso sobre otras pizarras y es un software ampliamente difundido en la comunidad educativa. Pero en mi opinión tiene varios problemas:

  • Es un software propietario: dependes de la empresa que lo desarrolla a la hora de sacar nuevas versiones, incluir mejoras y/o arreglar bugs.
  • Aunque en apariencia lo es, en realidad no es multiplataforma: para GNU/Linux quedó estancado en la versión 11, mientras que para Windows y OSX va por la versión 16. Lo mismo sucede con Interwrite Workspace y Pandectas: las versiones siguen líneas separadas de desarrollo a distintas velocidades y con distintas funcionalidades según el sistema operativo.
  • Puedes contratar servicios adicionales para que hagan versiones a medida para ti, pero la experiencia de otros proyectos es siempre lo misma: hay un periodo inicial de "luna de miel" en la que se atiende todo rápidamente, pero pasado el primer año la calidad del servicio va decayendo hasta que se abandona cualquier retroalimentación y posibilidad de continuar el trabajo.

Estos problemas son extensibles a cualquier solución propietaria por la propia idiosincrasia del software no libre.

La única manera que se me ocurre de evitar estos contratiempos es usando software libre y el único proyecto lo suficientemente avanzado que conozco es Open Sankoré.

  • Tiene la misma versión, 2.1.5 estable y 3.1 en desarrollo, para las 3 plataformas.
  • Está bajo licencia GPL y su código fuente es público y modificable por cualquiera, de tal forma que nuestras mejoras quedarían a disposición de la Comunidad Educativa a nivel internacional.
  • Tiene un repositorio púbico de recursos que se pueden reutilizar y al cual cualquiera puede contribuir.

Como desventajas se me ocurren:

  • Presumiblemente no tiene tantas funcionalidades como tienen los SW propietarios equivalentes. Eso es algo que deberían juzgar los expertos en el uso de PDI.
  • El repositorio github hace 2 años que no recibe actualizaciones, por lo que algún indocumentado que no sepa como funciona esto puede afirmar que es un "proyecto muerto". Bueno, está tan muerto como puede estarlo el Notebook de SmartBoard para Linux, que no recibe actualizaciones desde hace mas tiempo y que nos ha costado bastante trabajito hacerlo funcionar sobre Ubuntu Trusty (sin apoyo de Smart, of course). Si dedicas dinero el proyecto "resuciará" e irá progresando y estoy seguro de que es mas fácil hacer avanzar Open Sankoré que Smart Notebook.
  • No te darán soporte para hacerla funcionar con nuevas pizarras que se adquieran. No es problema: mi compañero Jaime ha hecho funcionar Open Sankoré con pizarras Galneo, aunque en principio no parecían compatibles. Normalmente es sencillo realizar estas tareas para un grupo tan preparado como son los administradores de los IES/CPR.

En conclusión:

  • Usar SW propietario es un parche cortoplacista que no vas a controlar nunca. Usar SW libre es un proyecto a medio y largo plazo en el que tú eres el dueño del producto.
  • Económicamente da lo mismo emplear el dinero en pagar licencias de SW propietario que invertirlo (usando recursos propios o recursos externos contratando con alguna empresa neutral) en mejorar un SW libre existente.
  • A nivel político-publicitario siempre se sacará mas rédito a hacer tu propio SW, siguiendo las peticiones y demandas de tu profesorado y poniendo de forma gratuita el resultado a disposición de otras Comunidades Autónomas y países.

Y esta es mi opinión. Me encanta discutir, así que se aceptan peros.

viernes, 5 de agosto de 2016

Xiaomi no mola

No todo es salir del paso y a veces lo que intentamos fracasa estrepitosamente, aunque esté considerado de mal gusto hablar de ello. Pues no será así hoy: de todas las cosas que me toca hacer hay veces que tiro horas por /dev/null sin lograr nada más que una merecida lección que me pone en mi sitio. Por ejemplo, si necesito bajarme los humos nada mejor que echar un rato con el ladrillo que antes era un Xiaomi Redmi 1S.

Me compré el móvil de segunda mano aproximadamente en julio de 2015. La gente contaba (y cuenta) maravillas sobre Xiaomi y sus estupendos productos, así que adquirí un móvil casi nuevo. Traía interfaz Miui vistosa y pulida, la cámara era bastante buena y en general el funcionamiento era ligero. Pero, vaya... la batería de 2000mAh se quedaba corta. No es tolerable que después de quitarlo del cargador a las 7:30 cuando llega la hora de comer, sin haber apenas tocado el móvil para una o dos llamadas breves y 4 whatsapps, estuviese la batería al 75%. Mis móviles Android anteriores, con menos batería y potencia no sufrían tal drenaje injustificado.

Buscando en Internet resulta que este comportamiento es normal ahora. Ya me ha pasado recientemente con otro móvil, un Doogee X5 Pro, que había que cargar a media tarde para poder usarlo hasta final de día (que es cuando usamos intensivamente el móvil los multipadres de estos tiempos). Por ese motivo ya no compro ningún móvil que tenga menos de 4000mAh de batería y directamente no me creo la historia de los que afirman que si, que les duran sus 2X00mAh hasta la noche con 4 horas de pantalla.

El Xiaomi Redmi 1S por lo visto podía mejorarse cambiando la ROM y poniendo luego un kernel ad-hoc que multiplicaba las horas de autonomía milagrosamente, ya que el software por defecto era bastante manirroto con el consumo de energía. Dediqué varios días a probar versiones sin ninguna mejora significativa que mereciese la pena ("...espera a que se calibre bien la batería, decían en los foros....¡ya!") ....hasta que sucedió la primera catástrofe.

Una noche cargué una ROM y al reiniciar no tenía señal de red telefónica. Ni 2G, ni 3G ni nada. Reinicié una vez mas y al volver tampoco tenía Wifi. Al día siguiente me puse a investigar y entonces me doy cuenta de que mi móvil ha perdido el IMEI y las MAC de la Wifi y el Bluetooth. Esos datos se guardan en diversas particiones del "disco duro" del móvil y por algún motivo se habían machacado. A partir de aquí aquí constato varias cosas:

  • Que la perdida de IMEIs, Baseband y MAC no es infrecuente en los Xiaomi.
  • Que si tienes CPU Mediatek es bastante sencillo fijar de nuevo el IMEI y otros datos perdidos, con el modo ingeniero o usando applicaciones de terceros como las Uncle Tool.
  • Que si tienes CPU SnapDragon, como es mi caso, estás jodido. No hay un método sencillo y los que probé no funcionaron.
  • No funcionó usando una esotérica aplicación llamada QPST y sus satélites QFil, eMMC downloader, etc.
  • No funcionó leyendo e intentando sacar algo en claro los delirantes, autoreferenciados y nada lógicos posts de la página turca de Androidbrick. Parecen una broma de Erdogan y los otomanos a Occidente en venganza por la batalla de Lepanto,
  • No funcionó pidiendo ayuda en los foros oficiales de Miui http://en.miui.com ni en los semioficiales http://miui.es, que además de tener una estética y contenido que parecerían naïf al mismo Doraemon tienen mucha paja entre la información relevante. Su único gran consejo era que "esperase a la siguiente ROM oficial y reflashease". Como si una ROM nueva fuera a traerme de vuelta las particiones perdidas.
  • Si que saqué claro que si tienes un móvil con SnapDragon no está de más hacer un backup de esas particiones usando adb y guardarlas en lugar seguro para restaurarlas si hay una catástrofe. Como dice mi amigo Pedro, mas vale un por si acaso que cien mecagoend10s. Aquí viene como hacerlo para un Redmi 1S como el mío. Para otros modelos las particiones no serían "mmcblk0p16_modemst1" y siguientes, pero no es díficil averiguar cuales son ya que la buena gente suele publicar eso para otros móviles.
    Hay incluso aplicaciones como ésta (manual) o ésta que te hacen el backup sin tener que teclear comandos mediante la shell del adb.
  • Por supuesto, intentar hablar directamente con Xiaomi o Qualcomm (fabricantes de los SnapDragon) usando sus soportes oficiales es como hablar con el Ser Inmutable de Parménides.
  • En la desesperación, encontré un post en indonesio en el que alguien compartía en Dropbox el backup de esas particiones. Lo descargué y lo probé sin éxito. En teoría eso equivale a clonar el IMEI y piensas que va a aparecer Jack Bauer por la ventana a detenerte, pero tampoco es para tanto.
  • La solución "oficial" es cambiar la placa base, pero si el móvil está fuera de garantía eso cuesta casi tanto como uno nuevo. Descartado.
Estaba resignado a usar el móvil de reproductor MP3, cámara de fotos y GPS, sin ninguna conectividad exterior, pero cualquier situación siempre es susceptible de empeorar: una mañana estaba cargando y se apagó para siempre. Nunca mas volvió a encender ni siquiera en modo Fastboot, aunque al conectarlo al puerto USB de un PC se detectaba algo durante un tiempo, al final no aparecía nada. Llevé el móvil a un par de técnicos y ambos me certificaron que tenía un ladrillo con la placa base frita. Llegados a este punto me rendí y dejé el móvil en un cajón. Pasado un año y aprovechando el tiempo libre del verano me decidí a darle una vuelta al tema. A lo largo del año habia ido acumulando alguna documentación nueva. Una de ellas era usar el método del cortocircuito para revivir al móvil: desmontándolo hay 2 puntos llamados "test point" que podemos puentear con un cable o unas pinzas y eso puede poner el móvil en un modo llamado "Qualcomm Download Mode o QDL" (que no es el modo Recovery ni Fastboot, sino otro modo un par de escalones mas cerca del Infierno) desde el que usando la herramienta MiFlash se podía cargar el firmware completo (usando una ROM Fastboot) y revivirlo. Los puntos a cortocircuitar uniéndolos son los dos círculos plateados bajo la ranura SIM izquierda:
Es importante deshabilitar de forma temporal el requisito de drivers firmados en Windows (o de forma permanente aquí) y preparar bien el cable para hacer el cortocircuto entre ambos test point. Para cortocircuitar yo he usado 3 pines para soldadura ya que casualmente la distancia entre el primero y tercero coinciden con la distancia entre los dos test point.
Para poder hacer el cortocircuito he unido ambos pines con un cable dupont hembra-hembra, quedando:
Una vez preparada la parte de hardware, instalamos MiFlash, deshabilitamos la firma de drivers en Windows, abrimos MiFlash y conectamos el cable USB de carga/datos al PC. Por otro lado, descargamos una ROM Fastboot para nuestro Redmi 1S y la descomprimimos, guardando los ficheros en una ruta corta y sin espacios en blanco, por ejemplo c:\armani (armani es el nombre en clave que pone Xiaomi al modelo Redmi 1S). Los ficheros descomprimidos estarán en c:\armani y c:\armani\images (por ejemplo debe haber un C:\armani\images\MPRG8626.mbn). En MiFlash le damos a Browse y seleccionamos el directorio c:\armani. A continuación realizamos el cortocircuito tocando primero el pin de la izquierda y con cuidado y lentamente el de la derecha, vigilando que no se desconecten, tal como se ve:
Sin soltar pinchamos el cable USB en el móvil y en este punto debe sonar el "tachán" de detección de un disposivo USB en Windows. Si no se detecta nada hay que desconectar repetir la realización del cortocircuito hasta que se detecte.
Una vez detectado, con la tercera mano damos al botón de actualizar en MiFlash y vemos que ya aparece un COMx conectando con el móvil en QDL mode (si lo listamos con lsusb aparece como 05c6:9008). Esto es todo un avance, ya que traemos el móvil desde un estado de muerte clínica y ahora al menos parece dispuesto a interactuar. ¿Que pasa si soltamos los cables y quitamos el cortocircuito aquí?. Mi experiencia es que el móvil ya está en modo QDL y no hace falta seguir cortocircuitando ambos test point. De todas maneras, también he probado a hacer todo manteniendo el cortocircuito. Continuemos: ahora le damos al botón "Flash" de MiFlash y comienza el proceso de flasheo de la ROM y vemos como van apareciendo mensajes en pantalla. Si todo va bien en unos minutos acaba todo y el móvil reinicia mostrando flamante el sistema operativo. En mi caso no va bien: tras 10 o 15 segundos se queda en un "wait device connect..." y al final acaba dando un error diciendo que los drivers no están firmados. No es eso, el error sucede tras el "Reboot to mini kernel" :
[00001794]CreateManagedObject(1392): Error no especificado(0x80131604)
[00001794]GetFactoryObject(1436): Error no especificado(0x80131604)
[00001794]CreateManagedObject(1392): Se ha intentado cargar un programa con un formato incorrecto.(0x8007000b)
[00001794]GetFactoryObject(1436): Se ha intentado cargar un programa con un formato incorrecto.(0x8007000b)
[00001794]GetFactoryObject(1457): El servicio especificado no existe.(0x800704db)
[00001794]GetSearchPath(1512): El servicio especificado no existe.(0x800704db)
[00001794]StartFlash(13): El parámetro no es correcto.(0x80070057)
[00001E64]CEmergencyFlasher::IsQPSTServer(655): No implementado(0x80004001)
[00001E64]COM10 0.05 Load programmer "C:\armani\images\MPRG8626.mbn"
[00001E64]DownloadFlashProgrammerDMSS(625): Se ha intentado cargar un programa con un formato incorrecto.(0x8007000b)
[00001E64]DownloadFlashProgrammer(946): Se ha intentado cargar un programa con un formato incorrecto.(0x8007000b)
[00001E64]COM10 0.05 Open programmer "C:\armani\images\MPRG8626.mbn"
[00001E64]COM10 0.05 Open serial port "\\.\COM10"
[00001E64]COM10 0.05 Receiving hello packet
[00001E64]COM10 0.05 Send hello response
[00001E64]COM10 0.05 ReadDataPacket id 13, offset 00000000, length 80
[00001E64]COM10 0.05 ReadDataPacket id 13, offset 0x000050, length 4096
[00001E64]COM10 0.06 ReadDataPacket id 13, offset 0x001050, length 4096
[00001E64]COM10 0.06 ReadDataPacket id 13, offset 0x002050, length 4096
[00001E64]COM10 0.06 ReadDataPacket id 13, offset 0x003050, length 4096
[00001E64]COM10 0.06 ReadDataPacket id 13, offset 0x004050, length 4096
[00001E64]COM10 0.06 ReadDataPacket id 13, offset 0x005050, length 4096
[00001E64]COM10 0.06 ReadDataPacket id 13, offset 0x006050, length 4096
[00001E64]COM10 0.06 ReadDataPacket id 13, offset 0x007050, length 4096
[00001E64]COM10 0.06 ReadDataPacket id 13, offset 0x008050, length 4096
[00001E64]COM10 0.06 ReadDataPacket id 13, offset 0x009050, length 972
[00001E64]COM10 0.06 EndTransferPacket id 13, status 0
[00001E64]COM10 0.06 Send done packet
[00001E64]COM10 0.06 Open boot file "C:\armani\images\8626_msimage.mbn"
[00001E64]COM10 0.06 Open serial port "\\.\COM10"
[00001E64]COM10 0.06 Send hello command 0
[00001E64]COM10 0.08 Enable trusted security mode
[00001E64]COM10 0.08 Open EMMC card USER partition
[00001E64]COM10 0.13 StreamWrite address 00000000, size 40960
[00001E64]COM10 0.20 StreamWrite address 0x00a000, size 40960
[00001E64]COM10 0.28 StreamWrite address 0x014000, size 40960
[00001E64]COM10 0.36 StreamWrite address 0x01e000, size 40960
[00001E64]COM10 0.44 StreamWrite address 0x028000, size 40960
[00001E64]COM10 0.52 StreamWrite address 0x032000, size 40960
[00001E64]COM10 0.59 StreamWrite address 0x03c000, size 40960
[00001E64]COM10 0.66 StreamWrite address 0x046000, size 40960
[00001E64]COM10 0.73 StreamWrite address 0x050000, size 40960
[00001E64]COM10 0.83 StreamWrite address 0x05a000, size 40960
[00001E64]COM10 0.89 StreamWrite address 0x064000, size 40960
[00001E64]COM10 0.95 StreamWrite address 0x06e000, size 40960
[00001E64]COM10 1.02 StreamWrite address 0x078000, size 40960
[00001E64]COM10 1.09 StreamWrite address 0x082000, size 40960
[00001E64]COM10 1.16 StreamWrite address 0x08c000, size 40960
[00001E64]COM10 1.22 StreamWrite address 0x096000, size 40960
[00001E64]COM10 1.31 StreamWrite address 0x0a0000, size 40960
[00001E64]COM10 1.38 StreamWrite address 0x0aa000, size 40960
[00001E64]COM10 1.44 StreamWrite address 0x0b4000, size 40960
[00001E64]COM10 1.52 StreamWrite address 0x0be000, size 40960
[00001E64]COM10 1.58 StreamWrite address 0x0c8000, size 40960
[00001E64]COM10 1.66 StreamWrite address 0x0d2000, size 40960
[00001E64]COM10 1.75 StreamWrite address 0x0dc000, size 40960
[00001E64]COM10 1.84 StreamWrite address 0x0e6000, size 40960
[00001E64]COM10 1.91 StreamWrite address 0x0f0000, size 40960
[00001E64]COM10 1.98 StreamWrite address 0x0fa000, size 40960
[00001E64]COM10 2.06 StreamWrite address 0x104000, size 40960
[00001E64]COM10 2.14 StreamWrite address 0x10e000, size 40960
[00001E64]COM10 2.22 StreamWrite address 0x118000, size 40960
[00001E64]COM10 2.30 StreamWrite address 0x122000, size 40960
[00001E64]COM10 2.38 StreamWrite address 0x12c000, size 40960
[00001E64]COM10 2.45 StreamWrite address 0x136000, size 40960
[00001E64]COM10 2.53 StreamWrite address 0x140000, size 40960
[00001E64]COM10 2.61 StreamWrite address 0x14a000, size 40960
[00001E64]COM10 2.69 StreamWrite address 0x154000, size 40960
[00001E64]COM10 2.78 StreamWrite address 0x15e000, size 40960
[00001E64]COM10 2.88 StreamWrite address 0x168000, size 40960
[00001E64]COM10 2.94 StreamWrite address 0x172000, size 40960
[00001E64]COM10 3.02 StreamWrite address 0x17c000, size 40960
[00001E64]COM10 3.09 StreamWrite address 0x186000, size 17920
[00001E64]COM10 3.13 Close EMMC card USER partition
[00001E64]COM10 3.14 Reboot to mini kernel
[00001E64]COM10 3.19 Wait device connect 0
[00001E64]COM10 4.22 Wait device connect 1
[00001E64]COM10 5.25 Wait device connect 2 
[00001E64]COM10 6.28 Wait device connect 3
[00001E64]COM10 7.31 Wait device connect 4
[00001E64]COM10 8.33 Wait device connect 5
[00001E64]COM10 9.38 Wait device connect 6
[00001E64]COM10 10.41 Wait device connect 7
[00001E64]COM10 11.44 Wait device connect 8
[00001E64]COM10 12.47 Wait device connect 9
[00001E64]COM10 13.50 Wait device connect 10
[00001E64]COM10 14.53 Wait device connect 11
[00001E64]COM10 15.56 Wait device connect 12
Y de aquí no salimos, parece que la carga del MiFlash no pasa de los primeros estadios. He probado diversas ROM y versiones de MiFlash por si fuera eso, sin éxito. A intentar hacerlo con la batería puesta de forma precaria, sin éxito. Y poco mas: mi móvil está tan dobleplusbrickeado que ni el QDL mode acaba de traerlo a la vida. Abandono de nuevo con el rabo entre las piernas y 6 u 8 horas de trabajo improductivo. Quizá el próximo año tenga mas soluciones o bien tenga que usar algo parecido JTAG para flashear directamente el dispositivo por hardware... No, en serio, creo que si no consigo una placa base barata lo que haré será venderlo por piezas. Esto ha sido un fracaso absoluto, con una serie de catástrofes inexplicables (¿borrarse el IMEI al actualizar una ROM? ¿no poder corregir ese IMEI? ¿borrarse el bootloader o algo similar de forma espontánea?) y ni Xiaomi ni Qualcomm han ayudado mucho. Como uno ya tiene una edad y eso le da el derecho humano a tener mas manías.... a partir de ahora Xiaomi y Qualcomm:


Vamos a disfrutar de la vida, que sin gobierno se vive muy bien y hasta nos perdonan la desviación del déficit nuestros amigos de la UE para no humillarnos. Estos imbéciles se piensan que yo soy tonto...