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

viernes, 20 de abril de 2018

RPG Maker MV en miniportátiles MSI con Ubuntu

Un docente de mi centro está trabajando en un proyecto para realizar aplicaciones educativas en forma de videojuegos de rol usando la herramienta RPG Maker MV, que permite generar un videojuego ejecutable en Linux, Windows, OSX, Android e iPhone.

El programa final es una aplicación portable que se lanza desde un ejecutable ./Game contenido en el directorio principal y que contiene un navegador Chrome/Chromium empotrado, en el cual se ejecuta la aplicación como si fuese de escritorio. Como lenguaje de programación se usa JavaScript y para la parte gráfica usa WebGL mediante PixiJS. El resultado es un videojuego de rol con gráficos en 2D del estilo de los venerables Zelda de los primeros tiempos. El contenido de la carpeta de la versión Linux tiene este aspecto:


Estamos en fase de pruebas del juego en las máquinas de los centros y un compañero nos avisó de que en los miniportátiles MSI L1350D la ventana se quedaba en negro y no mostraba nada. Lanzando el ejecutable Game desde terminal y revisando el montón de mensajes de log se aprecia el error:
GL_INVALID_OPERATION : glConsumeTextureCHROMIUM: invalid mailbox
Buscando un poco por Internet determino que es un error de WebGL en Chromium. No me extraña, ya había tenido antes problemas con páginas que usan WebGL y los navegadores. Normalmente son derivados de bugs o incompatibilidades en el driver de la tarjeta VGA. En el caso de los MSI tenemos una vieja:
00:02.0 VGA compatible controller: Intel Corporation Atom Processor D4xx/D5xx/N4xx/N5xx Integrated Graphics Controller, (8086:a011)
Una prueba rápida: si accedo al portátil con "ssh -X" y ejecuto el juego, si que se ve bien. Eso confirma que es un problema de las X. Los drivers están actualizados, así que por ahí hay poco que rascar. Una solución extrema es desactivar el DRI en un xorg.conf a medida o bien no cargar el módulo "glx". El problema es que esto afectaría al rendimiento de todas las X, no solo del juego, penalizando por tanto el uso normal del escritorio.

La opción mas deseable es arrancar el Chrome/Chromium con WebGL desactivado (usando el parámetro --disable-webgl) y ver si así funciona. El problema es que este Chromium está embebido en el juego...¿cómo manipular su arranque?. Pues investigando un rato veo que en el mismo directorio donde está ./Game hay un fichero llamado package.json con este contenido:
{
    "name": "KADOKAWA/RPGMV",
    "main": "www/index.html",
    "js-flags": "--expose-gc",
    "chromium-args": "--disable-setuid-sandbox",
    "window": {
        "title": "",
        "toolbar": false,
        "width": 816,
        "height": 624,
        "icon": "www/icon/icon.png"
    }
}
Cáspita, parece el fichero de configuración de arranque del Chromium. Si añado lo marcado en negrita:
{
    "name": "KADOKAWA/RPGMV",
    "main": "www/index.html",
    "js-flags": "--expose-gc",
    "chromium-args": "--disable-setuid-sandbox  --disable-webgl",
    "window": {
        "title": "",
        "toolbar": false,
        "width": 816,
        "height": 624,
        "icon": "www/icon/icon.png"
    }
}
Lo arrancamos... et voilá:


Todo funcionando. A otra cosa, mariposa.



lunes, 16 de abril de 2018

Captura de la pantalla de los alumnos (I)

Lamento este tiempo de silencio, he estado muy ocupado haciendo un Máster en Estupefacción.

Siempre es muy útil para el profesor controlar que uso están haciendo los alumnos con sus ordenadores en el aula. Para esto hemos usado hasta ahora Aulalinex o epoptes. El problema es que ambos son sencillos de usar para observar que hace un alumno concreto, pero no lo son para un grupo de ellos o todos a la vez. Además, desde hace un tiempo nuestro Aulalinex no acaba de funcionar al 100% en Ubuntu.

Un profesor me planteó la posibilidad de hacer una "foto" colectiva de todas las pantallas, que dejase las imágenes con las capturas de los escritorios en un directorio concreto para su consulta posterior. El problema es interesante, pero nos encontramos que aunque desde la óptica del profesor todo son aulas con ordenadores de alumnos, desde un punto de vista interno tenemos al menos 3 escenarios:

  • Aulas con thinclients, donde los ordenadores de los alumnos ejecutan su escritorio y aplicaciones dentro del ordenador del profesor. Sus pc son terminales tontos que apenas hacen nada que no sea conectarse remotamente y abrir sus sesiones en el pc del profesor a través de la red interna 192.168.0.X del cada aula.
  • Aulas con ordenadores independientes para alumnos dentro de una VLAN privada, con direcciones 192.168.0.X. Estos ordenadores pueden ser portátiles o sobremesa (aulas "infolab"), realmente son el mismo caso.
  • Aulas con ordenadores independientes para alumnos que no están aislados, sino que están en la red general del centro y tienen IPs 172.X.Y.Z.

Internamente, el manejo de esta casuística es muy diferente. Por ello iremos por partes y solucionaremos primero el caso de las aulas con thinclients, que es seguramente el más sencillo. En este escenario todas las sesiones están dentro del propio pc del profesor de tal manera que no hace falta ninguna conexión remota: todo queda en casa.

Lo primero es averiguar si hay alumnos en el aula conectados desde los thinclient. Eso se consigue lanzando el comando "who" en el pc del profesor:
cbayont04@a23-pro:~$ who
sjimenezt09 pts/5        2018-04-12 08:43 (a23-o03.local)
cbayont04    :0           2018-04-12 08:33 (:0)
sruizb13    pts/1        2018-04-12 08:43 (a23-o06.local)
........
Aquí se ve que hay un profesor en la consola (:0) y dos alumnos conectados remotamente desde los thinclients a23-o03 y a23-o06. El código para verificarlo será:
thinclients=$(who |  grep ".local)$")  #Si hay logeados usuarios con  el prefijo .local) al final estamos en un aula de thinclients y esos son los alumnos
if [ -z "$thinclients" ]
then 
   echo "No detecto thinclients. Abortando.
   exit 1
else #Son thinclients
   ...
Luego preparamos un directorio para grabar las capturas de la pantalla (en negrita):
pc=$(hostname)
fecha=$(date +%Y-%m-%d)
hora=$(date +%H:%M:%S)
destino="$HOME/capturas/$pc/$fecha/$hora"
rm -rf "$destino"
mkdir -p "$destino"
cd "$destino"
A continuación se identifican las IP de los pc encendidos mediante un nmap en el rango 192.168.0.200-253 (el usado en mi caso para los thinclients) e iteramos sobre ellas:
encendidos=$(nmap -oG - --system-dns  -sP 192.168.0.200-253 | grep -v '^#' | tr -d '()' | sed 's/.local//' | awk '{print $2}' | sort)
for ip in $encendidos
do
Seguidamente obtenemos el nombre del thinclient a partir de la IP (usando avahi-resolve-address ya que los thinclients no están dados de alta en nuestro servidor DNS y la resolución de nombres la realizan ellos mismos mediante el demonio avahi) y el nombre del alumno que ha hecho login en dicho thinclient.
pc=$(avahi-resolve-address $ip | cut -f2)  #El delimitador por defecto es  
if [ -n "$pc" ]    #Si resolvemos el nombre, esta operativo
then
  user=$(who | grep -i $pc | cut -d" " -f1)
  if [ -n "$user" ]  #Si tiene user logueado
  then
Por último ya solo queda capturar el escritorio del thinclient y copiarlo a la carpeta $destino. Para ello debemos averiguar la ruta del $HOME del alumno (con "getent passwd ..") y tomar la identidad de dicho usuario (con "su $user") para realizar la captura de su escritorio completo con:
home_user=$(getent passwd "$user" | cut -d: -f6)
su $user -c  "DISPLAY=$ip:7  XAUTHORITY=$home_user/.Xauthority import -window root /tmp/$user-$pc.jpg"
cp /tmp/$user-$pc.jpg $destino/$user-$pc.jpg
El comando anterior:
DISPLAY=$ip:7  XAUTHORITY=$home_user/.Xauthority import -window root /tmp/$user-$pc.jpg
digamos que lo he encontrado a base de prueba-error.

Para poder hacer la captura del escritorio del thinclient conectado remotamente hay que definir las variables DISPLAY y XAUTHORITY correctas para acceder a dicho escritorio con la credencial del alumno y tener los permisos adecuados. El acceso a las sesiones X desde otra sesión X es algo que está siempre bastante protegido para evitar espionaje entre usuarios y es complicado incluso para el usuario root. Finalmente la foto se guarda en /tmp/$user-$pc.jpg y de ahí la llevamos luego a $destino/$user-$pc.jpg.

Una vez recopiladas las capturas de todas las IP abrimos la carpeta $destino con thunar y así el profesor puede ver todas las imágenes cómodamente.

El script completo es:
# cat /usr/bin/captura-escritorio-todos
#!/bin/bash

thinclients=$(who |  grep ".local)$")  #Si hay logeados usuarios con  el prefijo .local) al final estamos en un aula de thinclients y esos son los alumnos

if [ -z "$thinclients" ]
then 
   echo "No detecto thinclients. Abortando."
   exit 1
else #Son thinclients
  pc=$(hostname)
  fecha=$(date +%Y-%m-%d)
  hora=$(date +%H:%M:%S)
  destino="$HOME/capturas/$pc/$fecha/$hora"
  rm -rf "$destino"
  mkdir -p "$destino"
  cd "$destino"

  #En los thinclients el DNS ip<-->nombre se publica desde cada puesto mediante avahi
  encendidos=$(nmap -oG - --system-dns  -sP 192.168.0.200-253 | grep -v '^#' | tr -d '()' | sed 's/.local//' | awk '{print $2}' | sort)
  for ip in $encendidos
  do
     pc=$(avahi-resolve-address $ip | cut -f2)  #El delimitador por defecto es  , por eso no uso -d
     if [ -n "$pc" ]    #Si resolvemos el nombre, esta operativo
     then
         user=$(who | grep -i $pc | cut -d" " -f1)
         if [ -n "$user" ]  #Si tiene user logueado
         then
             sudo /usr/bin/captura-escritorio-thinclient $user $ip $pc
             cp /tmp/$user-$pc.jpg $destino/$user-$pc.jpg
         fi
     fi
  done
  thunar "$destino"
fi

exit 0
El otro script usado es:
# cat /usr/bin/captura-escritorio-thinclient
#!/bin/bash

user=$1; ip=$2; pc=$3
home_user=$(getent passwd "$user" | cut -d: -f6)
su $user -c  "DISPLAY=$ip:7  XAUTHORITY=$home_user/.Xauthority import -window root /tmp/$user-$pc.jpg"
   
exit 0
Para que el el script llamado por el usuario normal pueda hacer el "su $user ..." necesitamos que esa parte se ejecute con permisos de root, que es el único usuario que puede adoptar la identidad de otro sin saber su contraseña. Por eso llevamos esa parte a otro script que ejecutaremos con "sudo". Evidentemente también hay que modificar /etc/sudoers para permitir su ejecución con sudo a todos los usuarios regulares del grupo teachers (profesores del centro).
# cat /etc/sudoers
....
....
%teachers ALL = (ALL) NOPASSWD: /usr/bin/captura-escritorio-thinclient
....
....
Al finalizar la captura de todos los escritorios de alumnos se abre la carpeta $destino con todas las imágenes de las capturas de escritorio para que el profesor pueda revisarlas tranquilamente con el visor de fotografías de nuestro sistema operativo:


Bueno, pues está resuelto el caso mas simple. Quedan dos pendientes para continuar la serie y esta vez no vamos a esperar tanto para continuar.

domingo, 18 de marzo de 2018

Ocultando el código de un script bash

A veces necesitamos un script bash que puedan ejecutar los usuarios (por ejemplo, mediante un acceso directo en un fichero .desktop), pero dentro de él hay contraseñas o algún fragmento código que no nos interesa hacer público.

Por poner un ejemplo práctico, imaginemos un script que levanta/apaga a voluntad la red wifi de 5ghz de nuestros puntos de acceso DLink, que en mi caso mantengo apagada por defecto.

El script es sencillo:
# cat wifi5ghz.sh
#!/bin/bash
case "$1" in
  "on")   comando="ifconfig ba0 up"
          ;;
  "off")  comando="ifconfig ba0 down"
          ;;
  *)      echo "Error en parámetros"
          exit 1
          ;;
esac
sshpass -p "tuyM59b" ssh -o StrictHostKeyChecking=no root@192.168.0.1 "$comando"
exit 0
Usamos sshpass para entrar por ssh y ejecutar el comandod de apagado/encendido sin que se pida contraseña al usuario. El problema que tenemos es que si distribuimos el script tal que así, cualquier usuario puede ver la contraseña de administración del router DLink (la que he puesto es figurada) y eso no es tolerable.

Entre las diversas soluciones a este problema una consiste en hacer el script ilegible ofuscando su contenido. De las herramientas y trucos que hay para eso el mas potente que he encontrado es usando la aplicación "shc", que compila un script generando un fichero ejecutable ilegible. Nosotros nos quedaremos con el código fuente del script y a los usuarios les distribuiremos el ejecutable. Es raro esto de compilar scripts, pero para la situación descrita viene de perillas.

Una vez instalado compilaremos el script haciendo:
# shc -r -f wifi5ghz.sh -o wifi5ghz
Esto nos creará un fichero ejecutable wifi5ghz que hará lo mismo que wifi5ghz.sh sin que sea visible su código (si el usuario hace un cat sobre él verá un galimatías ASCII). El parámetro "-r" es importante porque permite que ese ejecutable pueda ejecutarse en otras máquinas distintas a aquella dónde se compila el script (si no se pone el ejecutable deja de funcionar a los pocos días).

Como apunte adicional, si consultamos los parámetros de shc veremos que tiene cosas bastante interesantes, como por ejemplo la posibilidad de hacer que el ejecutable caduque en una fecha predeterminada.

Hasta pronto.

domingo, 4 de marzo de 2018

Ejecutar comandos de consola de forma remota en Windows.

Como buen fanático del terminal, siempre prefiero hacer cosas de administración de sistemas tecleando antes que con ratón. En Unix esto es lo más habitual, pero en Windows no lo ponen tan fácil.

En cualquier caso siempre viene bien tener la opción de conectar con una consola remota de Windows y escribir los comandos en ella, sin necesidad de desplazarnos físicamente a la máquina ni de iniciar una sesión remota completa con rdesktop. En principio con un servidor OpenSSH en el equipo destino es suficiente. Un servidor ssh es un software que en Linux viene de serie mientras que en Windows, entre varias opciones, podemos poner una versión GPL liberada por Microsoft.

Pero no, vamos a ver una forma alternativa de ejecutar comandos de consola de forma remota en Windows que no necesita instalar nada especial en el PC destino. Contemplaremos 2 métodos: lanzar la ejecución de los comandos desde un equipo con Windows y hacerlo desde un equipo con Linux.

1. Consideraciones previas.

Para hacer que nuestros Windows estén dispuestos a aceptar órdenes remotas hay que prepararlos antes tocando varias configuraciones:

1.1. Abrir el puerto 445.

Para comunicarnos y dar órdenes al Windows remoto necesitamos comunicar con él por su puerto 445, denominado "microsoft-ds", que sirve para un montón de cosas incluida la entrada de virus ;-).

Como este puerto está cerrado normalmente por el firewall de Windows debemos primeramente abrirlo para que acepte conexiones entrantes. Podemos hacerlo con el confuso interface gráfico de configuración del firewall y tardar varios minutos:



o bien abrir una consola de comandos en modo administrador y teclear:
netsh advfirewall firewall add rule dir=in action=allow protocol=TCP localport=445 name="Allow_TCP-445" 
Seguramente después haya que reiniciar el servicio de firewall para que se aplique de forma efectiva.

Supongo que con este ejemplo de método gráfico versus método de terminal queda claro por qué muchas veces es preferible usar la línea de comandos.

1.2. Modificar el registro para permitir el acceso a los "administrative shares"

Si el equipo remoto trabaja con Windows 10 hay que añadir una entrada al registro para permitir las conexiones entrantes que ejecutarán comandos, ya que por defecto UAC impide que usuarios administradores se conecten a los "administrative shares". De nuevo lo haremos desde consola:
reg add HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f
Si no creamos esta entrada de registro obtendremos errores de "Acceso denegado" al intentar ejecutar comandos remotos.

1.3. Solo para Linux: activar SMB v1.

Esto solo debe hacerse si el equipo desde el que lanzamos el comando es un Linux.

Debido a la aparición del ransomware WannaCry, que aprovechaba una vulnerabilidad en SMB llamada EternalBlue (con la que seguramente los servicios de seguridad de USA nos han estado espiando a todos durante años) hubo que improvisar soluciones transitorias . Una de ellas, rápida y sucia, era deshabilitar SMB1 en Windows y así impedir la entrada de WannaCry.

Como efecto colateral, el programa que usamos en Linux para mandar comandos al Windows deja de funcionar, ya que necesita que SMB1 esté activo. Por tanto, dependiendo que tengamos o no activo SMB1 en nuestro Windows podrá funcionar o no la ejecución remota. A día de hoy EternalBlue ya ha sido solucionado con los parches de Microsoft, por lo que SMB1 puede estar de nuevo activo.

Para ver su estado abrimos una consola de PowerShell y tecleamos "Get-SmbServerConfiguration"
PS C:\> Get-SmbServerConfiguration

AnnounceComment                 : 
AnnounceServer                  : False
AsynchronousCredits             : 64
AuditSmb1Access                 : False
AutoDisconnectTimeout           : 15
AutoShareServer                 : True
AutoShareWorkstation            : True
CachedOpenLimit                 : 10
DurableHandleV2TimeoutInSeconds : 180
EnableAuthenticateUserSharing   : False
EnableDownlevelTimewarp         : False
EnableForcedLogoff              : True
EnableLeasing                   : True
EnableMultiChannel              : True
EnableOplocks                   : True
EnableSecuritySignature         : False
EnableSMB1Protocol              : False       
EnableSMB2Protocol              : True
...
...
Ahí vemos EnableSMB1Protocol a False. También podemos verlo directamente con:
PS C:\> Get-WindowsOptionalFeature –Online –FeatureName SMB1Protocol
...
...
¿Cómo lo activamos? Con:
PS C:\> Enable-WindowsOptionalFeature -Online -FeatureName SMB1Protocol
Nos pedirá reiniciar para que sea efectivo el cambio. Este Windows es maravilloso: activas un protocolo y tienes que reiniciar la máquina completa, ahí queda eso.

Como curiosidad aquí tenemos recopilados todos los comandos para ver/cambiar el estado de los servicios SMBx.

2. Desde un equipo con Windows.

Bueno, ya tenemos el Windows remoto receptivo, vamos ahora a ver como darle órdenes. Necesitamos instalar las pstools en el PC desde donde daremos órdenes. Ojo: esto se instala en el PC desde donde se ejecuta el comando, el PC destinatario no necesita que instalemos nada, el único requisito para él es lo indicado en el apartado 1.

No viene mal echar un vistazo a todas las utilidades, son una maravilla que conviene poner de serie en todos nuestros Windows. La que usaremos nosotros es psexec. Veamos como ejecutar un comando remoto desde el Windows donde tenemos instalado psexec contra otro Windows:
psexec \\a20-o14 "ipconfig"
Esto anterior se ejecutaría usando las credenciales del usuario actual en el PC remoto. Si queremos dar otras credenciales especificamos el usuario (que debe ser un administrador) y contraseña:
psexec -u administrador -p password \\a20-o14 "ipconfig"

PsExec v2.2 - Execute processes remotely
Copyright (C) 2001-2016 Mark Russinovich
Sysinternals - www.sysinternals.com

Starting PSEXESVC service on a20-o14...........
Configuración IP de Windows

Adaptador de Ethernet Ethernet:

Sufijo DNS específico para la conexión. . : vguadalupe
Vínculo: dirección IPv6 local. . . : fe80::f938:6376:3936:6a45%3
Dirección IPv4. . . . . . . . . . . . . . : 172.24.XXX.12
Máscara de subred . . . . . . . . . . . . : 255.255.255.0
Puerta de enlace predeterminada . . . . . : 172.24.XXX.2

Adaptador de túnel isatap.vguadalupe:

Estado de los medios. . . . . . . . . . . : medios desconectados
Sufijo DNS específico para la conexión. . : vguadalupe

Como se ve conectamos con el equipo a20-o14 y ejecutamos el comando "ipconfig" sobre él, dándonos la dirección IP y configuración de red el equipo. Con:
psexec \\a20-o14 "cmd"

PsExec v2.2 - Execute processes remotely
Copyright (C) 2001-2016 Mark Russinovich
Sysinternals - www.sysinternals.com

Starting PSEXESVC service on a20-o14...........

Microsoft Windows [Versión 6.3.9600]
(c) 2013 Microsoft Corporation. Todos los derechos reservados.

C:\Windows\system32>

Se nos abre una consola de comandos remota, que ejecutará en la otra máquina lo que tecleemos.

Si alguna de las dos órdenes anteriores produce errores del tipo:
Couldn't access a20-o14:
No se ha encontrado la ruta de acceso de la red.
Make sure that the default admin$ share is enabled on a20-o14.
En mi caso era síntoma de que el puerto 445 estaba cerrado. Si ese es tu caso, abrelo como hemos comentado en la parte 1 y ya debería funcionar. Si además dice:
PsExec v2.2 - Execute processes remotely
Copyright (C) 2001-2016 Mark Russinovich
Sysinternals - www.sysinternals.com
Couldn't access a20-o14:
Acceso denegado.
Entonces tendremos que añadir la entrada de registro descrita en la parte 1.2.

Mas cosas interesantes relacionadas con psexec:

  • Como ejecutar en varios PC a la vez el mismo script almacenado en un servidor:
    psexec \\computername1,computernamfe2,computernameN -d -u usuario -p password \\servidor\scripts\script.bat
    
    Esto es parecido al comando dsh de Linux.
  • Con el modificador -c podemos enviar desde el ordenador local un fichero .exe para ejecutarlo remotamente:
    psexec \\computername1,computernamfe2,computernameN -d -c programa.exe -u usuario -p password programa.exe
    
  • Para ver cuantas sesiones hay abiertas en una máquina remota ejecutamos el comando de Windows "query session":
    psexec \\a20-o19 query session
    
    NOMBRE DE SESIÓN  NOMBRE DE USUARIO     ID  ESTADO TIPO   DISPOSITIVO
    >services                                0  Desc
    console           GM_SEGUNDO             1  Activo
    rdp-tcp#1         Administrado           2  Activo
    rdp-tcp                               5536  Escuchar
    
    Vemos que en consola hay una sesión abierta con el usuario GM_SEGUNDO y en remote desktop hay otra abierta con el usuario Administrador (¿cómo consigo sesiones de escritorio de usuarios concurrentes sobre un mismo Windows?: instalando rdpwrapper).
  • Psexec está concebido para ejecutar comandos de consola, con entrada/salida en texto. Cualquier aplicación gráfica que lancemos aparecerá en el escritorio remoto. Por ejemplo:
    psexec \\a20-o19 -i 1 -d notepad
    
    Hará que al usuario GM_SEGUNDO del ejemplo anterior (el de la sesión con ID 1, de ahí el parámetro "-i 1". Este es el valor por defecto) se le abra el bloc de notas en la pantalla ante su total estupefacción. Esta es la teoría, pero en las pruebas prácticas que he hecho se abre una ventana con el contenido en negro y que no permite interactuar. Debe ser algún bug o feature de Windows 10.

    Si queremos lanzar aplicaciones gráficas en un Windows remoto y que aparezcan en nuestro escritorio local (sería una conexión Remota tipo VNC o Remote Desktop pero a nivel de aplicación en lugar de a nivel de escritorio completo) habría que usar SeamlessRDP, pero ese tema escapa al contenido de este artículo.

A modo de resumen: psexec es adecuado para ejecutar comandos de terminal de forma remota sin tener que iniciar sesión en los escritorios Windows. Como truco: cuando queremos ejecutar varios comandos la mejor solución es ponerlos dentro de un script .bat en una carpeta compartida por Samba accesible por todos los Windows y lanzar dicho script desde psexec.

3. Desde un equipo con Linux.

Bueno, ¿y que pasa si el equipo cliente es un Linux y desde él queremos ejecutar los comandos remotamente en nuestros Windows? ¿Hay algun psexec para Linux?

Pues si hay algo que se le parece: winexe, que sigue la idea de usar el puerto 445 para mandar ordenes a los Windows de forma remota. Es un proyecto algo abandonado y del cual no hay paquetes oficiales en .deb ni en .rpm (para Manjaro/Arch por supuesto que sí, pero es que ahí jugamos en otra liga). Además es fácil encontrar la versión 1.0, pero la que ahora funciona con Windows 10 es la 1.1.

Al final lo he encontrado aquí, con versiones .deb para Debian y Ubuntu. En mi caso he bajado el paquete winexe-static-1.1-0-jessie.deb para ejecutarlo desde mi servidor montado Debian Jessie.

El paquete se llama "static" porque tiene las librerías de Samba metidas dentro del ejecutable durante la compilación. La causa es que al cambiar la versión de Samba esto tiende a fallar, así que han optado por llevarlas al estilo años 70, embebidas en el ejecutable para evitar errores.

# dpkg -i winexe-static-1.1-0-jessie.deb
# winexe-static
winexe version 1.1
This program may be freely redistributed under the terms of the GNU GPLv3
Usage: winexe-static [OPTION]... //HOST COMMAND
Options:
  -h, --help                                  Display help message
  -V, --version                               Display version number
  -U, --user=[DOMAIN/]USERNAME[%PASSWORD]     Set the network username
  -A, --authentication-file=FILE              Get the credentials from a file
  -N, --no-pass                               Do not ask for a password
  -k, --kerberos=STRING                       Use Kerberos, -k [yes|no]
  -d, --debuglevel=DEBUGLEVEL                 Set debug level
  --uninstall                                 Uninstall winexe service after
                                              remote execution
  --reinstall                                 Reinstall winexe service before
                                              remote execution
  --system                                    Use SYSTEM account
  --profile                                   Load user profile
  --convert                                   Try to convert characters
                                              between local and remote
                                              code-pages
  --runas=[DOMAIN\]USERNAME%PASSWORD          Run as the given user (BEWARE:
                                              this password is sent in
                                              cleartext over the network!)
  --runas-file=FILE                           Run as user options defined in a
                                              file
  --interactive=0|1                           Desktop interaction: 0 -
                                              disallow, 1 - allow. If allow,
                                              also use the --system switch
                                              (Windows requirement). Vista
                                              does not support this option.
  --ostype=0|1|2                              OS type: 0 - 32-bit, 1 - 64-bit,
                                              2 - winexe will decide.
                                              Determines which version (32-bit
                                              or 64-bit) of service will be
                                              installed.
Como se ve los parámetros son muy distintos a los de psexec, ya que es una herramienta independiente. En este enlace se ve un buen repaso de todos ellos.

Veamos como ejecutar un comando:
# winexe-static --convert -U administrador%password //a20-o14 "ipconfig"
Error: error Unknown argument (get codepage)
CTRL: Probably old version of service, reinstalling.

Configuración IP de Windows

Adaptador de Ethernet Ethernet:

Sufijo DNS específico para la conexión. . : vguadalupe
Vínculo: dirección IPv6 local. . . : fe80::f938:6376:3936:6a45%3
Dirección IPv4. . . . . . . . . . . . . . : 172.19.XXX.100
Máscara de subred . . . . . . . . . . . . : 255.255.255.0
Puerta de enlace predeterminada . . . . . : 172.19.XXX.2

Adaptador de túnel isatap.vguadalupe:

Estado de los medios. . . . . . . . . . . : medios desconectados
Sufijo DNS específico para la conexión. . : vguadalupe
O abrir un interpréte de comandos remoto y escribir las órdenes allí:
# winexe-static  --convert -U administrador%password //a20-o04 "cmd"
Microsoft Windows [Versión 6.3.9600]
(c) 2013 Microsoft Corporation. Todos los derechos reservados.

C:\Windows\system32>cd \users
cd \users

C:\Users>dir
dir
El volumen de la unidad C no tiene etiqueta.
El número de serie del volumen es: B62C-6CE1

Directorio de C:\Users

16/06/2016  08:09    DIR          .
16/06/2016  08:09    DIR          ..
26/01/2017  12:45    DIR          Administrador
22/08/2013  16:36    DIR          Public
20/07/2017  05:43    DIR          UpdatusUser
28/07/2017  08:04    DIR          usuario
0 archivos              0 bytes
6 dirs  33.118.711.808 bytes libres

C:\Users>exit
exit
# 
Si en algún momento da este error:
# winexe-static -U administrador%password //a20-o04 "cmd"
ERROR: Failed to open connection - NT_STATUS_CONNECTION_RESET
La causa mas probable es que esté desactivado SMB1 en el PC remoto, lo cual se soluciona como vimos en el apartado 1.

Finalizamos con una recopilación de errores:
  • ERROR: Failed to open connection - NT_STATUS_LOGON_FAILURE : credenciales incorrectas.
  • ERROR: CreateService failed. NT_STATUS_ACCESS_DENIED : puerto 445 cerrado o registro no modificado según apartado 1.1 y 1.2.
  • ERROR: Failed to open connection - NT_STATUS_CONNECTION_RESET : servicio SMB1 deshabilitado. Habilitar según apartado 1.3 .

Y con esto ya tenemos expuestas todas las posibilidades para interactuar con nuestros Windows desde terminal.


Me despido con una imagen impactante que no tiene nada que ver con el blog, pero que está aquí al lado y no puedo dejar pasar:


Esto tiene 66.700 años según las últimas dataciones y es la prueba mas antigua de arte realizada por un homo sapiens de la especie vecina, la neanderthalensis. En esa época los homo sapiens sapiens estábamos empezando a salir de África por Oriente Próximo y andábamos ocupados en otras cosas. Y aquí, al lado de la Ribera del Marco ya había una especie que desarrollaba pensamiento simbólico en este planeta. Impresionante.

Es nuestro pequeño Gobekli Tepe, espero que sepamos cuidarlo.


jueves, 22 de febrero de 2018

Montemos una IP-Webcam barata - Reloaded III

Este tema es inacabable. Después de todos los posts sobre la cámara IP a partir de una cámara usb y un router ADSL casero con OpenWRT/LEDE todavía me siguen saliendo cositas y ampliaciones cada pocos meses, así que no me queda otra opción que seguir revisitando el tema. Hagamos una retrospectiva:


Ahora el problema es que, recordemos, el guardado de las imágenes de captura se realizaba en una carpeta de un servidor remoto montada por sshfs. No es infrecuente que haya algún problema de red y esa conexión quede interrumpida. No siempre es restaurada esa conexión en tiempo y forma y a veces me encuentro con que llevamos varios días desechando imágenes ya que en el mermado espacio de almacenamiento del router ADSL no se puede guardar nada.

Para evitar esto he añadido código para que cuando se detecte que se ha perdido el montaje remoto por sshfs se envíe un correo especial de aviso, para que al menos pueda ponerle remedio cuanto antes. Marco en negrita la parte con el pequeño fragmento de código nuevo (el resto es como la ha ido quedando las últimas veces):
# cat /root/controlador.sh
#!/bin/ash

log() {
  test $montado -eq 1 && echo "$1" >> /mnt/snapshot/log.txt  
}

email() {
  test $email -eq 1 && echo -e "$1" | sendmail correo.aviso@gmail.com
}

monta_sshfs() {
  sshfs -o ssh_command="ssh -i /root/.ssh/id_rsa -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" -o nonempty openwrt@192.168.0.25:/home/openwrt /mnt
}

envia_secuencia() {

   if [ -e /tmp/motion.txt ]
   then

      #Recopila todos los ficheros de /tmp/motion/txt y los envia en un correo

      ficheros=$(cat /tmp/motion.txt | tr '\n' ' ')
      rm /tmp/motion.txt

      log "Historia de capturas $ficheros"
      zip -9 /mnt/escena.zip $ficheros

      echo "Secuencia $1" > /mnt/mensaje.txt
      test $email -eq 1 && mutt -s "Evento camara" correo.aviso@gmail.com -a /mnt/escena.zip < /mnt/mensaje.txt

      rm /mnt/escena.zip
      #Si no hay acceso al almacenamiento remoto, borramos las capturas para no llenar el disco del router.

      test $montado -eq 0 && rm -rf $destino

   fi

}

#Parametro 1: start, picture, end
#Parametro 2: fecha
#Parametro 3: nombre fichero (opcional)

#Obtenemos fecha y hora por si queremos poner algun filtro sobre ella y solo avisar en determinados
#momentos

time=$(date +%s)
anio=$(date +%Y @$time)
mes=$(date +%m @$time)
dia=$(date +%d @$time)
hora=$(date +%H @$time)
minuto=$(date +%M @$time)
diasemana=$(date +%u @$time) #El 1 es lunes
destino="/mnt/snapshot/$anio-$mes-$dia"
montado=1
email=0

if [ $diasemana -ge 6 -o $hora -le 7 -o $hora -ge 17 ]  # sabado/domingo o cualquier dia antes de las 8:00 o despues de las 17:00
then
   email=1
fi

#Si existe el fichero /mnt/testigo no se ha montado directorio remoto por sshfs,
#Intentamos montarlo y otra vez y luego preguntamos de nuevo.
#Si no se ha montado nada es que no se puede guardar nada de forma permanente ya que estamos escribiendo en la
#memoria interna del router y eso se llena rapido

test -e /mnt/testigo || monta_sshfs

if test -e /mnt/testigo
then
  #No está montado el directorio remoto, no hay donde guardar las imagenes
  montado=0
  #No hay almacenamiento por dias, no vamos a guardar tanto tiempo el fichero.
  destino="/mnt/snapshot"
  #Si no se ha avisado antes se avisa por correo
  if ! test -e /tmp/avisado
  then
     touch /tmp/avisado
     echo -e "Subject: Camara sin almacenamiento\r\n\r\nSe ha perdido la conexión remota con el directorio de almacenamiento de la cámara" | sendmail correo.aviso@gmail.com
  fi
else
  #Tenemos montado el directorio remoto, borramos el testigo de aviso.
  rm -f /tmp/avisado
fi

test -d $destino || mkdir -p $destino

case $1 in

  "start")
     log "Detectado inicio de movimiento $2" 
     email "Subject: Evento camara\r\n\r\nDetectado inicio de movimiento $2"
     #El fichero motion.txt tiene dos finalidades: 1) testigo para indicar que estamos detectando movimiento 
     #                                             2) guarda los nombres de los ficheros de captura de las fotos
     touch /tmp/motion.txt
     ;;
  "picture")
     fichero=$(basename $3)
     log "Guardando imagen $2 : $destino/$fichero" 

     #Si estamos en una ráfaga de movimiento detectado, guardamos el nombre de fichero con la foto.
     test -e /tmp/motion.txt && echo "$destino/$fichero" >> /tmp/motion.txt

     #Se guarda el fichero en el almacenamiento destino
     mv "$3" "$destino/$fichero"

     #Si no está montado el almacenamiento remoto y vemos que llevamos mas de 10 imagenes en
     #movimiento tenemos que borrarlas y enviarlas ya mismo, para no saturar el espacio.
     if [ $montado -eq 0 ]
     then
        #Si estamos en una ráfaga de movimiento detectado....
        if [ -e /tmp/motion.txt ]
        then
          lineas=$(wc -l /tmp/motion.txt | cut -d" " -f1)
          test $lineas -gt 10 && envia_secuencia $2
        else
          #Si no lo estamos, es una captura *snapshot* regular sin interés, la borramos.
          rm -f "$destino/$fichero"
        fi  
     fi
     ;;
  "end") 
     log "Detectado fin de movimiento $2"
     envia_secuencia $2
     ;;
   *) log "Evento $1"
esac


#Borra fichero "sent" creado por sendmail si existe, para liberar espacio
rm -rf /root/sent
rm -rf /sent
Para evitar enviar el mensaje en cada invocación del script se usa un fichero "avisado" en /tmp/ como bandera para verificar si se ha enviado o no ese mensaje. Ese fichero se borra cuando se detecta que se ha montado el directorio remoto o al reiniciar el equipo (todo el contenido de /tmp se borra en cada reinicio).

Bueno, pues seguro que vuelve la burra al trigo pronto y estamos otra vez aquí.



Hasta siempre Forges, me has hecho reírme de mí mismo muchas veces.

lunes, 19 de febrero de 2018

Ejecutar en los infolabs aplicaciones gráficas entrando con "ssh -X"

Esta mañana tenía que instalar Adobe Air y una aplicación .air remotamente en varios infolabs y como el instalador es "al estilo Windows" debía entrar por "ssh -X" y lanzar el ejecutable gráfico de instalación.

Me ha sorprendido bastante que fallase con el error de que no se podía abrir el display, como si no tuviera permisos para ejecutar aplicaciones X. La verdad es que nunca había tenido necesidad de ejecutar aplicaciones gráficas en remoto entrando por ssh en los infolab. He probado varias aplicaciones y en todas había problemas del tipo:
Failed to open display
o
Error: GDK_BACKEND does not match available displays
Lo primero ha sido mirar en /etc/ssh/sshd_config y ver que aparece:
X11Forwarding yes
Ante esto he quedado desconcertado un rato, hasta que he visto que ya lo solucionó mi compañero Manuel del IES Eugenio Hermoso. Hay que añadir a /etc/ssh/sshd_config la línea:
X11UseLocalHost no
Y reiniciar ssh en el infolab. ¡Gracias, Manolo!

¿Por qué esta línea no es necesaria en otros equipos como los Siatic y compañía? Pues no sabemos.

domingo, 18 de febrero de 2018

Windows: actualiza como puedas.

Vaya por delante que opino que usar Windows en un centro educativo es, salvo casos muy justificados, un disparate económico, ético y tecnológico. Pero por desgracia esa puerta quedó abierta en tiempos pasados y debemos lidiar con la situación como buenamente podamos.

1. Parte de guerra.

Una vez tienes instalados tus Windows "pelados" aparte de los problemas típicos de gestión de usuarios y administración te encuentras con la cuestión de sus actualizaciones, que tiene una idiosincrasia especial en un entorno como el nuestro. Repasemos:

Primero. Cualquier usuario, incluidos los defensores mas acérrimos, habrán comprobado que Windows tiene la irritante costumbre de actualizarse sin control y sin contemplaciones de forma extemporánea: al iniciar, al apagar o en medio de la operación de un PC. De una extraña manera, estas actualizaciones incluso no dudan en arrasar cuando les parece con el arranque dual haciendo desaparecer Linux del menú de arranque. Esto en mi opinión roza lo delictivo.

Segundo. Windows tiene un sistema de actualizaciones totalmente ilógico: si dejas un equipo sin actualizar 6 meses al lanzar el update no instala lo último, sino que pasa por casi toda la secuencia de actualizaciones que se han quedado atrás (pocas veces una actualización es descartada en favor de otra posterior), reiniciando el equipo varias veces. Eso, para la gente razonable acostumbrada a derivados de Debian y a las rolling relaease como mi querida Manjaro es sencillamente inconcebible. Me ha llegado a pasar que instalas un Windows 7 en una hora y luego te pasas 20 horas descargando actualizaciones por fases de descarga-instalación-reinicio hasta tenerlo al día.

Por otro lado, el proceso de actualización es tremendamente oscuro y nunca sabes que está pasando y si el sistema se ha quedado parado en alguna operación. Sabes cuando empieza y cuando acaba, pero no como avanza. Para los acostumbrados a la verbosidad de las actualizaciones en Linux este mutismo es incomprensible.

Tercero. Como ya avisamos en su momento a la gente que decide, para poner orden en este caos hace falta un sistema que nos permita administrar y dosificar el flujo de actualizaciones. Eso implica un Windows Server y un servicio WSUS por centro junto con el hardware para ello, lo cual representa un sensible gasto adicional en dinero y tiempo para administrarlo. Esto no se tuvo en cuenta por las mentes pensantes que decidieron adquirir licencias de Windows sin tino y nos dejaron el papelón a los de abajo.

También puedo hablar según mi experiencia: habiendo servido durante varios años en ICM, la antigua Agencia de Informática y Comunicaciones de la Comunidad de Madrid (muy conocida por colaborar con las tramas corruptas Púnica y Lezo; tranquilos: yo soy inocente, todo eso pasó mayormente mientras estaba de excedencia) donde todo se basaba en Windows. Incluso con toda la infraestructura de clientes y servidores Windows montada para gestionar las actualizaciones de forma controlada los problemas en los clientes eran constantes: parches que se enrocaban en una instalación iniciada e interrumpida infinitamente, equipos en que fallaba algo y se quedaban atrás sin actualizar, errores y pantallazos azules en arranques tras actualizaciones fallidas... y todo esto con Windows XP, en los que el que ritmo de actualizaciones era mucho mas reducido que en los Windows posteriores.

Cuarto. Para mas INRI, esto último no sirve nada tan pronto como comprendes la realidad de funcionamiento de los PC de los centros educativos. Esto no es una oficina al uso donde los PC se encienden de 8 a 15 o de 9 a 17. Un PC en un centro educativo se enciende y se apaga de forma aleatoria a lo largo del día según el uso en las materias y horarios de clase. Incluso podemos encontrarnos con PC que no se encienden durante muchos días y de repente luego se encienden una mañana entera con 3 reinicios al cambiar de clase. Evidentemente disparar unas actualizaciones que pueden tardar horas en un entorno tan aleatorio es un proceso abocado a la catástrofe: tanto por el consumo de ancho de banda que se incrementa de golpe al encender un grupo de PC de alumnos, así como por el ralentizamiento del PC asociado a la actualización y los problemas derivados de apagarlos cuando están a medias.

Cinco. Podríamos pensar que los PC de uso de los profesores (salas comunes, aulas, departamentos) si que están encendidos de forma continua. Falso: son ordenadores de uso compartido y una de las pequeñas luchas que tenemos los administradores informáticos es limitar la pulsión que tienen muchos usuarios de apagar el sistema operativo cuando se acaba su sesión, máxime teniendo en cuenta que en 5 minutos va a haber otro docente sentado en ese mismo sitio. Pues bien: no hay manera, cuando alguien quiere apagar, apaga.

Seis. ¿Puede empeorar la cosa? Si: las aulas de portátiles. Nada mas terrible que ir a guardar un portátil en un armario de carga porque acaba la clase y encontrarnos que nos dice que esperemos porque hay que instalar 13 actualizaciones. O encenderlo para empezar la clase y esperar 10 minutos a que se actualice. Pero eso no es todo: tenemos 20 portátiles conectados a un punto de acceso wifi normal y corriente pugnando por actualizar, descargando megas y megas cada uno e impidiendo el uso normal de todos los dispositivos conectados a la misma wifi. Como seguramente en una hora de clase no de tiempo a descargar todo en la próxima sesión volveremos a la casilla de salida.


2. Estrategias paliativas.

Ante este panorama no nos queda otra que lidiar como buenamente podamos con todo ello. Si quedamos las actualizaciones a su libre albedrío la tragedia en forma de sistemas dañados por el apagado en medio de una actualización o redes colapsadas está garantizada. Parafraseando el proverbio chino: simplemente tenemos que sentarnos a la orilla del río y esperar hasta que pasen los Windows muertos flotando corriente abajo. El problema es que al final esos Windows tenemos que resucitarlos nosotros.

En mi caso he optado por dos estrategias para evitar la debacle:

  1. Cuando es posible por la potencia del equipo cliente virtualizo los Windows y los dejo con las actualizaciones desactivadas. Tengo un master que actualizo de vez en cuando en un PC concreto y distribuyo luego el fichero .VDI (imagen del disco duro) a todos los demás.
  2. Si no es posible virtualizar, porque los PC andan justitos de procesador y memoria opto por dejar un arranque dual y: desactivar en la medida de lo posible las actualizaciones automáticas de Windows, usar un sistema basado en wsusoffline, como recomienda nuestro compañero Esteban, para actualizar contra un repositorio interno al IES y no contra Internet (con lo cual ahorramos tráfico de red) y cada cierto tiempo me toca perder varios días actualizando semi-manualmente los equipos.

Vamos a ver esto con detalle.

3. Parar, reanudar y limitar las actualizaciones.

No es plato de buen gusto parar las actualizaciones de un PC, se supone que incluyen mejoras y parches contra agujeros de seguridad como Wannacry, Meltdown o Spectre. Pero cuando la alternativa es tener el aula parada y los usuarios malhumorados porque todo el tiempo y ancho de banda se va en actualizar dices "¡pero que coño!" y paras todo.

La forma más efectiva que he encontrado de parar las actualizaciones automáticas es con estos comandos que se pueden meter en un script:
sc config wuauserv start= disabled
net stop wuauserv
reg add HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU  /v NoAutoUpdate /t REG_DWORD /d 1 /f
Con esto el Windows queda congelado en el tiempo salvo que Microsoft use algún truco artero para colarnos algo, tal como hace con esas instalaciones de Cortana u OneDrive que reaparecen después de haberlos eliminado una y otra vez. Si queremos volver a activar haremos los pasos contrarios:
sc config wuauserv start= auto
net start wuauserv
reg add HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU  /v NoAutoUpdate /t REG_DWORD /d 0 /f
Otra opción que puede resultar interesante es usar una característica que tiene Windows de definir una conexión inalámbrica de red como "metered" o de uso medido. Eso viene a significar que le avisamos de que esa conexión nos cuesta dinero cada megabyte y que por tanto, tenga ojito con lo que se descarga por ella. Pensemos por ejemplo en una conexión móvil 4G, un operador de wifi o el futuro Starlink de Elon Musk, que nos facturase por datos transferidos.

Para ello debemos establecer la conexión a la red y una vez hecha tecleamos:
netsh wlan show profiles
Esto nos mostrará el nombre de la conexiones wlan (redes wifi o 4G), por ejemplo algo así como "Airtel-WRTR301GN-8897_1". Una vez sabido el nombre, con:
netsh wlan show profile name="Airtel-WRTR301GN-8897_1"
Vemos los parámetros de la conexió. En ellos el parámetro "Cost" puede valer Unrestricted (no limitado) o Fixed (limitado). Por tanto, si queremos indicar que la conexión es metered hacemos:
netsh wlan set profileparameter name=”Airtel-WRTR301GN-8897_1″ cost=Fixed
Esto hará que Windows se lo piense antes de consumir ancho de banda en una actualización por esa conexión. Pero, ojo, esto no descarta todas las actualizaciones y las que se consideren críticas se realizarán. Aunque está concebido para conexiones inalámbricas, también podemos activarlo en conexiones cableadas trasteando el registro.

4. Encauzar las actualizaciones con WSUS Offline Update.

WSUS Offline Update es un sistema montado para realizar las actualizaciones de los Windows/Office usando la red local y minimizando el tráfico externo. Incluso permite actualizar Windows/Office sin conexión a Internet, descargando las actualizaciones a un pendrive y actualizando luego con él. Yo lo descubrí, como tantas otras cosas, gracias a mi compañero Esteban.

Todo rota en torno a 3 elementos:

  • Una aplicación/script que descarga las actualizaciones y parches disponibles para los sistemas seleccionados.
  • Un repositorio donde guardar lo descargado. Traduciendo: una carpeta local o de red donde guardar los archivos.
  • Una aplicación/script que examina el sistema Windows y actualiza con los parches pendientes.

Una visión detallada del sistema la podemos encontrar aquí.

En mi caso no he usado las aplicaciones gráficas para realizar las tareas, ya que como se deducirá me va mas la línea de comandos. Además he intentado que las dos primeras partes se realicen con Linux y un servidor samba. Solo la parte de aplicación de las actualizaciones es, evidentemente, sobre Windows. Para ello me he guiado por este manual.

En un servidor auxiliar creo una carpeta /datos/wsus, con permisos 777 para todo su contenido. Sobre esa carpeta descomprimo la última versión de wsusoffline, que a fecha de escribir este post es la 11.1.1.

Una vez descomprimido el .zip escribo el script que me hará la descarga de los parches y actualizaciones para los sistemas que le indique:
# cat /datos/wsus/update.sh
bash /datos/wsus/wsusoffline/sh/download-updates.bash w100 esn /includedotnet /includemsse /includewddefs /verify
bash /datos/wsus/wsusoffline/sh/download-updates.bash w63-x64  esn /includedotnet /includemsse /includewddefs /verify
bash /datos/wsus/wsusoffline/sh/download-updates.bash w100-x64 esn /includedotnet /includemsse /includewddefs /verify
# chmod +x datos/wsus/update.sh
Este script descarga lo que haya de Windows 10 (64 y 32 bits) y Windows 8 (64 bits). Mirar la documentación para ver todas las posibles opciones de descarga (Windows 7, Office, Visual C++, .NET, ...). Lanzamos la ejecución del script y nos vamos a hacer otras cosas, porque tarda un rato en descargar todo:
# /datos/wsus/update.sh
Cuando termina, vemos que ha hecho:
# du -sh /datos/wsus/wsusoffline/client
2,6G w100
4,8G w100-x64
1,9G w63-x64
# ls -1 /datos/wsus/wsusoffline/client/w100-x64/glb/
windows10.0-kb3172729-x64_bb12a14ec3891ec0a9e24edb529632263783d389.cab
windows10.0-kb3172729-x64_f4fc9775baa98c176f43e87c40088231a884122b.cab
windows10.0-kb3173427-x64_d95e56e499e2c281a1f59585221dc891253414c7.cab
windows10.0-kb3173427-x64_e3da65fe753d24a1759cdd029028cde743a62a23.msu
windows10.0-kb3173428-x64_52fa3686737353fae20ab55fa9c924bd90558a31.cab
windows10.0-kb4035632-x64_ea26f11d518e5e363fe9681b290a56a6afe15a81.msu
windows10.0-kb4049011-x64_a58e4c340939a7b23b86055a18abdc9c59308094.msu
windows10.0-kb4049065-x64_f92abbe03d011154d52cf13be7fb60e2c6feb35b.msu
windows10.0-kb4056887-x64_0fcf1ff448cea9474ea089a3d866beeb7212cec1.cab
windows10.0-kb4056887-x64_12a57a1104466ca878eb096fefa6c6babe520810.cab
windows10.0-kb4056887-x64_1e5c03724988979684c35a5493829e4abe9bdbfc.cab
windows10.0-kb4056887-x64_57d92c622280f34d0ee271a9c58fdce91c3c6808.cab
windows10.0-kb4056887-x64_8ad98c5fb14f2938536d794074a5b901b6eb0d72.cab
windows10.0-kb4056888-x64_5943823d032a25e40f8eee1613aa849d3963bd1d.cab
windows10.0-kb4056890-x64_2d0216b0e6b49f457e5111fbd7d766984af3f6cf.cab
windows10.0-kb4056891-x64_99b9dadbd6a71c8c9ca58b8e53285f8320dd32e3.cab
windows10.0-kb4056892-x64_39198b373a07390a3afdf2a64d19f24d59fca7a6.cab
windows10.0-kb4056893-x64_f025805bafd32c5f9d7ca37eb255a894dfb025d8.cab
windows10.0-kb4058702-x64_4ed8d0df4f3c190d3e423bf287d7e95a21a9124a.msu
Y ahí vemos todos los ficheros con las distintas actualizaciones y parches descargados esperando para ser aplicados según necesite el cliente Windows. Este script lo ejecutaremos de vez en cuando o al menos cuando se actualice wsusoffline.

Estos ficheros hay que compartirlos usando una carpeta samba de solo lectura accesible desde los Windows:
# cat /etc/samba/smb.conf
...
...
[wsus]
comment = WSUS Windows Updates
path = /datos/wsus
writable = no
browseable = yes
guest ok = yes
force directory mode = 0777
...
...
Reiniciamos samba y desde un Windows podemos abrir una ventana de comandos con credendiales de usuario administrador y teclear:
net use z: \\ip-servidor\wsus /persistent:no
Z:\wsusoffline\client\cmd\DoUpdate.cmd
Con lo cual empezará el laaaargo proceso de actualizaciones, que puede durar varias horas. En la ventana de terminal nos va informando escuetamente de cada parche aplicado. No nos desanimemos: si fuese mediante actualizaciones online podría tardar varios días y saturar la conexión de red del centro. De esta manera al menos tenemos controlado lo que se va haciendo y que se va actualizando.

5. Cosas a tener en cuenta.

Esto no es un camino de rosas, simplemente es algo para aminorar los problemas. Por eso debemos tener en cuenta varias cosas:

  • El wsusoffline es el sistema mas rápido si tenemos varios PC con Windows y el que menos tráfico de red genera, pero va siempre desactualizado respecto a los repositorios oficiales. Hay que vigilar si hay versiones nuevas de vez en cuando para actualizalo. A fecha de escribir esto la última actualización descargada es KB4058702, pero en Microsoft van por la KB4074608, que además es incompatible con la anterior, lo cual puede causar problemas en el script.
  • El update mas fiable es el realizado online contra los repositorios de Microsoft. El problema es que puede tardar mucho tiempo, descargar varios gigas y exigir varios reinicios. Multiplica eso por el número de Windows de tu red. De todas formas, si no nos queda otro remedio que hacerlo para salir de alguna situación complicada podemos abrir de forma directa la ventana para actualizaciones haciendo en un intérprete de comandos de Windows:
    C:\Windows\System32\control.exe /name Microsoft.WindowsUpdate 
    
  • Una alternativa a lo anterior o un método para salir de un atasco en que todas las actualizaciones fallan porque hay que subir de versión (por ejemplo, pasar de la 1703 a la 1709 en Windows 10) es descargar la última ISO de Windows (a día de hoy la 1709), montarla con wincdemu y actualizar desde allí.

Después de todas estas actualizaciones es bueno saber en que versión tenemos el Windows. Por ahí se comenta que ejecutando en una consola Powershell:
Get-CimInstance Win32_OperatingSystem | Select-Object buildnumber,version
Se muestra la versión, pero es falso ya que no sale completo todo el número de compilación. La manera de saberlo es con:
winver
Nos muestra:


Este Windows tiene por tanto en el momento en que escribimos esto la versión 1709, compilación 16299.192. Esta bastante actualizado a día de hoy, si buscamos en internet el "Historial de actualizaciones de Windows 10" vemos:


Podemos ver que nuestro Windows está en la compilación .192 y según la página de Microsoft posteriormente "sólo" han salido la 201, 214 y la 248. Cuando empecé a elaborar esta entrada ibamos por la 214 y ya ha salido otra, ahí es nada. Es verlo y me da la bajona... vaya cruz.