Ya estamos preparando el salto a Ubuntu 18, motivo por el cual estoy atareado como gato en matanza y escribo poco por aquí. En nuestros planes esta seguir con las aulas de thinclient usando como clientes ordenadores de hace 13 años.
Me llena de orgullo y satisfacción verlos ejecutando Libreoffice 6 y Firefox 60 con fluidez mientras los miniportátiles comprados años después echan el bofe abriendo páginas de diarios regionales. Ahí va un video un Fujitsu P300 con 1Gb de RAM, un procesador Pentium IV y una tarjeta gráfica que da vergüenza ajena:
Debido a problemas con la tarjeta de red de los Fujitsu P300 hemos mantenido congelado el kernel de la serie 3.X con un driver retocado que soporta el encendido remoto mediante WOL. Mi compañero Francis se ha ocupado de integrar el entorno de soporte de los thinclients en Ubuntu 18 y ha estimado con muy buen criterio que no es necesario actualizar la versión de la imagen y es mejor quedarla en Ubuntu 14.
A fin de cuentas el único propósito existencial de la imagen de thinclients es levantar una conexión gráfica remota con el servidor de aula, que si corre Ubuntu 18, por lo que una vez inicia sesión el alumno todo funciona en ese entorno y el Ubuntu 14 queda oculto entre bambalinas.
Después de configurar el entorno LTSP como mandan los cánones siempre tenemos unos cuantos problemillas de ajustes que de una vez para otra se repiten y hay que tirar de nuestra memoria para solucionarlos. Estos cambios ya están integrados en la imagen que nos van a distribuir de Ubuntu 18 para LTSP, pero ahora voy a dejarlo anotado como chuleta para cuando pasemos a Ubuntu 22 y nuestros Fujitsu P300 sigan dando el callo junto con la Curiosity en Marte.
resolv.conf: los thinclients en ejecución deben tener el resolv.conf de nuestro centro, para poder conectar con otras máquinas si es necesario. Esto se hace poniendo el nameserver/domain del resolv.conf que queremos en la ruta /opt/ltsp/i386/etc/resolvconf/resolv.conf.d/original y regenerando la imagen del cliente con ltsp-update-image.
avahi: los clientes se anuncian a si mismos en la red del aula con el nombre "$HOSTNAME.local". De esta forma es fácil identificarlos y acceder a ellos sin averiguar su IP. Para que se anuncien es necesario que avahi esté activado en la imagen de los thinclients, pero por defecto este servicio está parado debido a que está en la lista negra de /usr/share/ltsp/init-ltsp.d/50-rm-system-services. Si quitamos avahi-daemon de ese fichero y regeneramos la imagen del cliente ya funcionará.
autenticación en thinclients: cuando hacemos alguna variación en el LTSP (cambio de nombre, clonado, etc) los alumnos no pueden iniciar sesión en los thinclients, dando error de credenciales. En apariencia todo esta bien (configuracion de pam, nsswitch, etc). La causa real es que entre servidor y thinclients se hace una conexión SSH y hay que regenerar esas claves usando "ltsp-update-sshkeys" y reconstruyendo luego la imagen.
Cuando haga la instalación del entorno LTSP en las Siatic subiré una guía. Nos vemos.
Me ha llegado una tablet Android baratuna moribunda de Hogarium que se queda en la pantalla de inicio sin cargar el sistema. Lo normal en esos casos es arrancar pulsando la teclas Power+Vol Down o Up, con lo que entramos en el recoverý de Android y allí hacemos un Factory Reset. Pero en esta tablet se resistía: después de dejarme los dedos cadavéricos apretando no había manera de entrar en el menú de recovery.
Bueno, no hay nada que no se pueda hacer con una buena línea de comandos. Así que enchufé la tablet a mi Manjaro Linux y tecleé:
# adb devices
....
# adb shell
Bien... me dejaba conectar con el adb del Android y entrar en el shell para ejecutar comandos. La tablet no estaba tan muerta como parecía. Ahora pongo:
# adb reboot recovery
Y reiniciamos el sistema entrando en el recovery.
Ahora solo tengo que moverme con las teclas de volumen y hacer un "Wipe data/factory reset" y "Wipe cache" para restaurar la tablet a fábrica y ver si funciona. Horror, compruebo que siguen sin funcionar la teclas de volumen. En este punto solo hay dos explicaciones: o esas teclas están averiadas (lo cual, como a Rajoy, no me consta) o bien el firmware de la tablet es tan cutre que no trae el driver para manejarlas hasta que no se ha cargado el sistema.
¿Qué hago?: al conector USB micro del tablet (el típico de carga de los móviles) conecto un cable OTG
y a éste un teclado USB. Entro de nuevo en el recovery et voilá... puedo moverme por el menú con las teclas subir/bajar y ejecutar las acciones con Enter. Ya si puedo hacer un Factory Reset y de la Caché. Minutos después tenemos la tablet arrancada ejecutando el asistente de configuración de Android. Otro aparato salvado de la quema.
Por cierto, una vez arrancado el Android completo las teclas de volumen si funcionan :-D.
En el anterior artículo vimos como capturar una imagen de las escritorios de los thinclients en un servidor de aula.
En el presente veremos como capturar las pantallas de pc normales (portátiles o pc de sobremesa). Aunque visualmente no hay diferencia, el reto es ahora es distinto ya que en este escenario los escritorios a capturar corren en pc remotos cuyas sesiones se ejecutan físicamente fuera del ordenador del profesor. En los thinclients todo eran tareas realizadas dentro del propio servidor de aula.
Para esta entrada asumimos que todos los pc de alumnos están dentro de una VLAN privada del aula, con direccionamiento 192.168.0.X.
La idea del proceso es:
En los PC de los alumnos hay un script que al ejecutarse hace una captura del escritorio y manda la pantalla al PC del profesor por algún medio.
En el PC del profesor hay un script que rastrea el aula en busca de PC de alumnos encendidos y ejecuta remotamente el script anterior en paralelo sin que haya petición de contraseña.
Todas las imágenes recopiladas se reunen en un único directorio y se abren para que el profesor pueda verlas.
En primer lugar, ¿cómo hacemos que el desde el pc del profesor se pueda ejecutar algo en los pc de los alumnos sin pedir contraseña?... pues con una relación de confianza. Esto puede automatizarse para que una vez generada la clave pública se distribuya mediante puppet a todos los pc de alumnos usando el recurso ssh_authorized_key.
En segundo lugar, ¿cómo hacemos para ejecutar un comando a la vez en varias máquinas desde el pc del profesor?...pues hay múltiples alternativas. En nuestros centros tenemos la suite "utilaula", desarrollada por nuestro compañero Ricardo, que incluye el script ejecutaenhosts:
ejecutaenhosts -p comando
y que ejecuta el comando indicado en paralelo en todos los pc de alumnos que encuentra dentro del aula en el espacio 192.168.0.X. Al final de esta entrada muestro una versión reducida de este script, pero cada cual puede usar la técnica que desee de las enumeradas en el enlace anterior.
En tercer lugar ¿cómo enviamos la imagen capturada al pc del profesor?. Evalué varias alternativas: copiarlas por scp desde el pc del profesor, enviarlas por tftp desde los pc de los alumnos, enviarlas por netcat ...al final la más simple que encontré es usar una carpeta samba para que los clientes dejen los ficheros y después recogerlos el profesor. Es una técnica que ya tengo montada en mi IES para otros scripts y siempre me ha funcionado bastante bien.
1. Script de captura en los pc de los alumnos.
Vamos primero a ver el script de captura que pondremos en todos los pc de los alumnos:
# cat /usr/bin/captura-escritorio
#!/bin/bash
directorio=$1
pc=$(hostname)
user=$(who | grep "(:0)" | head -1 | cut -f1 -d" ")
if [ -n "$user" ]
then
su $user -c "DISPLAY=:0 import -window root /tmp/$user-$pc.jpg"
cd /tmp
smbclient -N //172.X.Y.Z/almacen -c "cd $directorio; put $user-$pc.jpg"
fi
exit 0
Comentemos:
Toma un parámetro de entrada que será el directorio donde se dejará la imagen capturada del escritorio usando smbclient para subir el fichero a la carpeta remota.
La captura se hace de una forma similar a como se hacia en la entrada pasada, con su $user -c "DISPLAY=:0 import -window root /tmp/$user-$pc.jpg".
Envía la captura a una carpeta compartida por samba llamada "almacen" en el servidor 172.X.Y.Z, tal como describimos aquí.
2. Scripts en el pc del profesor.
A continuación vemos el programa que ordena la ejecución del script anterior en todos los pc de alumnos, que irá en sudoers ya que se ejecutará como root (esto también sucedió en la parte I de esta serie de entradas).
De nuevo toma un parámetro de entrada que será el directorio dentro de "almacen" donde los clientes dejarán la imagen de captura.
Usa ejecutaenhosts para lanzar el comando en paralelo en todos los alumnos conectados dentro de la red privada del aula. Como dijimos antes, ejecutaenhosts es un script nuestro de los centros, pero se puede usar cualquier otro método.
Por último, el script que ejecutará el profesor y que lanza todo el proceso:
El nombre del directorio donde guardar las imágenes dentro de //172.X.Y.Z/almacen lo formamos con 12 caracteres aleatorios y lo creamos remotamente.
Creamos una carpeta local en el home del profesor con el pc, la fecha y la hora de la captura.
Llamamos al script de captura mediante sudo. Cuando acaba recogemos todas las capturas de "almacen", las metemos en la carpeta local, borramos la carpeta remota y abrimos "thunar" para mostrarlas al profesor
Como vemos, el resultado final es el mismo que en la entrada anterior, solo que la forma de conseguirlo es bastante distinta dada la diferente arquitectura de funcionamiento del aula.
Se aconseja poner al profesor un fichero .desktop en el escritorio para ejecutar "captura-escritorio-todos".
3. Ejecución en paralelo.
Pongo una versión light de ejecutaenhosts para que lo adaptes a tus necesidades si no lo tienes. Necesitamos que, tal como hemos comentado, la clave pública ssh haya sido repartida previamente a los alumnos para evitar que se pida la contraseña con cada ssh.
# cat /sbin/ejecutaenhosts
#!/bin/bash
if [ "$1" \= "-p" ] ; then
enparalelo="yes"
shift
fi
#Busca los hosts conectados en la vlan en el rango 200-253
listahosts=$(nmap -oG - --system-dns -sP 192.168.0.200-253 | grep -v '^#' | tr -d '()' | sed 's/.local//' | awk '{print $3 ";" $2}' | sort)
if [ -z "$listahosts" ]; then
echo "No se ha encontrado ninguna maquina conectada"
exit 0
fi
for hostip in $listahosts
do
host=$(echo $hostip | cut -d";" -f1)
ip=$(echo $hostip | cut -d";" -f2)
ssh -o StrictHostKeyChecking=no -o ConnectTimeout=9 -o ServerAliveCountMax=2 -o ServerAliveInterval=15 root@$ip $* > /dev/null 2>&1 &
done
echo -n "Esperando a que terminen los procesos "
for job in $(jobs -p)
do
echo -n "."
wait $job
done
echo -e "\n"
echo "Hecho!"
exit 0
Y con esto ya estamos, solo nos queda un caso más para tener cerrada la serie.
Hace ya tiempo que no dedico una entrada al SAI, pero como se me estropeó el que tenía y recibí uno de reemplazo, al conectarlo y monitorizarlo de nuevo he aprovechado para probar y cerrar temas pendientes. Las entradas precedentes eran:
En el apartado 5 de la última entrada dejaba abierto el problema del apagado del servidor cuando está funcionando con baterías, un tema peliagudo que no tenía muy probado por falta de tiempo y oportunidad. No es plan desconectar el SAI de la corriente y ver que pasa en horario de producción. Ahora si he probado con calma y estas son las conclusiones.
1. Ficheros de configuración básica.
Empecemos repasando como tenemos los ficheros básicos en /etc/nut:
/etc/nut/hosts.conf
MONITOR salicru@localhost "UPS Virgen de Guadalupe"
/etc/nut/nut.conf
MODE=standalone
/etc/nut/ups.conf
maxretry = 3
[salicru]
driver = blazer_usb
port = auto
subdriver = cypress
protocol = mustek
desc = "SAI Salicru"
vendorid = 0665
productid = 5161
bus = "004" # adaptalo a tu caso
/etc/nut/upsd.conf
LISTEN 127.0.0.1 3493
#IP del servidor donde esta conectado el SAI con el cable USB.
LISTEN 172.20.123.2 3493
CMDSCRIPT /usr/bin/upssched-cmd
PIPEFN /tmp/upssched.pipe
LOCKFN /tmp/upssched.lock
AT ONBATT * START-TIMER ups-on-battery 15
AT ONLINE * CANCEL-TIMER ups-on-battery
AT ONLINE * EXECUTE ups-back-on-line
AT REPLBATT * EXECUTE ups-change-battery
AT LOWBATT * EXECUTE ups-low-battery
AT FSD * EXECUTE ups-fsd
AT SHUTDOWN * EXECUTE ups-shutdown
AT COMMOK * EXECUTE ups-comunication-ok
AT COMMBAD * EXECUTE ups-comunication-bad
Of course, en todo lo anterior pondremos el usuario que nos apetezca (en lugar de admin_sai), contraseña y direccionamiento IP correspondiente. Los que he puesto yo son de pega.
2. Proceso de apagado desde nut.
Con calma he leído todo lo que he encontrado sobre el proceso de eventos que genera NUT cuando el SAI está funcionando con batería y empieza a descargarse. Repasamos la secuencia de eventos:
El SAI está operando con corriente y con los 2 leds de la derecha del frontal encendidos. Se va la corriente eléctrica y se activa la batería del SAI. De los 6 leds que tiene se encienden en verde los 5 de la derecha, a modo de indicador de carga máxima y comienza a sonar un beep cada pocos segundos. Se irán apagando conforme se descargue la bateria y el beep sonará cada vez con mayor cadencia.
Si miramos el estado del SAI con "upsc salicru ups.status" vemos que está en "OB", On Battery. El demonio ups-monitor ha enviado el evento ONBATT para que lo procese el ups-scheduler.
Pasa el tiempo y la batería se va descargando. Con "upsc salicru battery.charge" podemos ver el % de carga.
Algunos SAI tienen un parámetro battery.charge.low que permite definir el umbral de carga mínima de la batería. Ese umbral se puede redefinir poniendo "override.battery.charge.low = 25" en /etc/nut/ups.conf, pero nuestro Salicru no lo tiene y el umbral está fijado en el 10%. Podemos poner dicho parámetro, reiniciar el demonio y ver con "upsc salicru" que battery.charge.low = 25, pero a la hora de la verdad dicho valor es ignorado y todo se comporta como ese 10% estuviese escrito en piedra.
En general: la forma de determinar si la batería está baja depende el SAI/driver concreto y se calcula en función de battery.charge/battery.charge.low y battery.runtime/battery.runtime.low.
Pasado el umbral de batería baja se genera un evento LOWBATT para que lo procese el ups-scheduler. Aquí empieza la fiesta.
Si nuestro nut tiene esclavos (como vimos en la entrada anterior del blog), se les notifica un evento FSD (forced shutdown). A su vez, cada esclavo:
Genera un evento SHUTDOWN.
Espera FINALDELAY segundos(tipicamente 5).
Ejecuta su propio SHUTDOWNCMD.
Desconecta del upsd maestro.
El nut maestro, si ha enviado el FSD a los esclavos espera HOSTSYNC segundos (típicamente 15) para darles tiempo a desconectar. Pasado esto se envía un FSD a si mísmo, lo cual:
Genera un evento SHUTDOWN.
Espera FINALDELAY segundos(tipicamente 5).
Crea el fichero POWERDOWNFLAG - usualmente /etc/killpower.
Ejecuta su propio SHUTDOWNCMD.
A diferencia del resto de código, el comando SHUTDOWNCMD se ejecuta con permisos de root. Esto es debido a que siempre hay en marcha dos instancias de upsmon, una con el usuario "nut" y otra con el usuario "root". Está última está casi siempre ociosa y solo existe para ejecutar lo que diga el parámetro SHUTDOWNCMD definido en upsmon.conf.
Esta es la teoría, haciendo una prueba en entorno real vamos a describir lo que pasa en la práctica:
Tengo conectado al SAI una fuente del servidor principal, un servidor auxiliar y un monitor. Desconecto el SAI de la corriente.
El parámetro ups.status se pone en OB. battery.charge baja rápidamente en menos de un minuto del 100% al 85-88%. Esto pinta mal.
Se estabiliza y empieza a bajar despacio, con los leds frontales apagándose conforme avanza la carga. Este es el ritmo:
HORA
CARGA
STATUS
EVENTO
16:40
100%
OL
16:41
100%
OB
ONBATT
16:42
88%
OB
17:09
69%
OB
17:24
65%
OB
17:42
29%
OB
17:45:11
15%
OB
17:45:25
12%
OB
17:45:51
10%
OB LB FSD
LOWBAT, FSD
17:45:56
4%
OB LB FSD
EJECUCIÓN SHUTDOWNCMD
17:46:11
0%
OB LB FSD
17:46:26
42%
OL FSD
VUELVE LA CORRIENTE
ONLINE
Para hacer el cuadrante anterior he capturado los datos con este script:
Hay una descarga rapidísima al comienzo, de un 12% en cuestión de segundos.
Luego va bajando con suavidad durante una hora. A los 30 minutos está al 70%. A los 60 llega al 15%.
Cuando llega al 15% empieza a bajar de nuevo en caída libre y en 2 minutos llega al 0%.
Al bajar del 10% se generan los eventos LOWBATT y FSD. Pocos segundos después se llama a SHUTDOWNCMD con credenciales de root.
Con la batería al 0% no se corta la corriente, pero no he querido tentar cuanto aguanta así hasta el apagado físico real.
Al conectar de nuevo el SAI a la corriente vuelve a cargar y el estado OB se transforma en OL, pero se queda activado el flag FSD ya que no ha llegado a suceder el apagado del servidor.
En resumen: el SAI aguanta 60 minutos o más con 2 servidores y un monitor, pero tiene una curva de descarga bastante acelerada al comienzo y al final. Desde que se genera el evento LOWBATT hasta que se llega al 0% de carga pasan segundos, lo que queda muy poco tiempo de maniobra si queremos apagar varias máquinas.
Una segunda cosa a que destacar que el SAI queda en estado "FSD OL" al volver la corriente en el último momento. Para quitar el flag FSD sin reiniciar el servidor hay que reiniciar el demonio nut-server, pero al hacer eso algunas veces (no siempre) se genera un evento FSD y se ejecuta un SHUTDOWCMD. Esto puede provocar que si no tenemos precauciones con lo que se hace en SHUTDOWNCMD se apague el servidor estando el SAI ya con corriente externa.
En general, siempre que llegamos al estado FSD (incluso manualmente haciendo "/sbin/upsmon -c fsd") tarde o temprano se ejecutará SHUTDOWNCMD, por lo que es algo que habrá que tener en cuenta.
En el siguiente apartado veremos como he abordado las cuestiones planteadas.
3. Configuración del apagado.
Ya que los pocos segundos que transcurren desde que se genera el LOWBATT+FSD hasta que la batería llega al 0% no me inspiran ninguna confianza lo que voy a hacer es que cuando se lleven 30 minutos de batería (momento en que está está sobre el 70%) se apague el servidor de forma segura.
Podría forzar más tiempo, pero si en media hora no ha vuelto la corriente parece que la cosa va para largo y... ¿para que esperar lo inevitable?
Modificamos /etc/nut/upssched.conf para incluir un nuevo timer de 1800 segundos:
CMDSCRIPT /usr/bin/upssched-cmd
PIPEFN /tmp/upssched.pipe
LOCKFN /tmp/upssched.lock
AT ONBATT * START-TIMER ups-on-battery-shutdown 1800
AT ONLINE * CANCEL-TIMER ups-on-battery-shutdown
AT ONBATT * START-TIMER ups-on-battery 15
AT ONLINE * CANCEL-TIMER ups-on-battery
AT ONLINE * EXECUTE ups-back-on-line
AT REPLBATT * EXECUTE ups-change-battery
AT LOWBATT * EXECUTE ups-low-battery
AT FSD * EXECUTE ups-fsd
AT SHUTDOWN * EXECUTE ups-shutdown
AT COMMOK * EXECUTE ups-comunication-ok
AT COMMBAD * EXECUTE ups-comunication-bad
Los eventos son gestionados con /usr/bin/upssched-cmd:
#! /bin/bash
#
# This script should be called by upssched via the CMDSCRIPT directive.
#
# Here is a quick example to show how to handle a bunch of possible
# timer names with the help of the case structure.
#
# This script may be replaced with another program without harm.
#
# The first argument passed to your CMDSCRIPT is the name of the timer
# from your AT lines.
function mailSend() {
echo "$2" | mail -s "$1" -a "From: Avisos.ies " tu.correo@gmail.com
}
MESSAGE_MAIL=""
EVENT_TYPE=$1
APAGADO=0
FECHA=$(date)
case "$EVENT_TYPE" in
"ups-on-battery-shutdown")
#Saltado evento AT ONBATT * START-TIMER ups-on-battery-shutdown 1800: llevamos 30 minutos con bateria. Apagamos.
MESSAGE_MAIL="UPS on battery: shutdown now"
APAGADO=1
;;
"ups-on-battery")
MESSAGE_MAIL="UPS on battery: warning"
;;
"ups-comunication-bad")
MESSAGE_MAIL="Communications with UPS lost"
;;
"ups-change-battery")
MESSAGE_MAIL="UPS battery needs to be replaced"
;;
"ups-back-on-line")
MESSAGE_MAIL="UPS on line power"
;;
"ups-low-battery")
MESSAGE_MAIL="UPS battery is low"
;;
"ups-comunication-ok")
MESSAGE_MAIL="Communications with UPS established"
;;
"ups-shutdown") # Llega tras el FSD
MESSAGE_MAIL="FSD: shutdown message"
;;
*)
MESSAGE_MAIL="Aviso tipo: $EVENT_TYPE"
;;
esac
mailSend "$FECHA => $MESSAGE_MAIL" "[UPS] Event $EVENT_TYPE de SAI Virgen de Guadalupe:"
echo "$FECHA => SAI: $MESSAGE_MAIL" >> /var/log/sai.log # /var/log/sai.log permisos 664 y root:nut
if [ $APAGADO = "1" ]
then
sleep 30
/sbin/upsmon -c fsd # Esto genera un evento ups-fsd y un evento ups-shutdown, que a su vez llama a SHUTDOWNCMD como root.
fi
La mayoría de los eventos mandan un correo y escriben en el log /var/log/sai.log. Tan sólo es difrente el salto del timer ups-on-battery-shutdown lanza una orden "/sbin/upsmon -c fsd", que genera a su vez un evento FSD y posteriormente dispara la ejecución de SHUTDOWNCMD, que apunta a /root/scripts/apagar_servidores.sh:
#!/bin/bash
function mailSend() {
echo "$2" | mail -s "$1" -a "From: Avisos.ies " tu.correo@gmail.com
}
FECHA=$(date)
estado=$(upsc salicru ups.status 2> /dev/null)
en_bateria=$(echo $estado | tr ' ' '\n' | grep "OB")
if [ -z $en_bateria ] #Si en up.status no parece OB, no estamos en bateria. Es un SHUTDOWNCMD innecesario
then
MESSAGE_MAIL="Evento SHUTDOWNCMD pero estado $estado. No apagamos el servidor"
mailSend "$FECHA => $MESSAGE_MAIL" "[UPS] Evento SHUTDOWNCMD"
echo "$FECHA => SAI: $MESSAGE_MAIL" >> /var/log/sai.log # /var/log/sai.log permisos 664 y root:nut
else
MESSAGE_MAIL="Apagado servidor por evento SHUTDOWNCMD"
mailSend "$FECHA => $MESSAGE_MAIL" "[UPS] Evento SHUTDOWNCMD"
echo "$FECHA => SAI: $MESSAGE_MAIL" >> /var/log/sai.log # /var/log/sai.log permisos 664 y root:nut
ssh root@servidor-auxiliar "/sbin/shutdown -h +0"
sleep 10
/sbin/shutdown -h +0
fi
exit 0
El script anterior recordemos que se ejecuta como root.
Primero comprueba que el SAI sigue en estado OB (en bateria). Si no es así, manda un mensaje diciendo que aunque se haya recibido un FSD-SHUTDOWN no se apagará nada. Esto previene que si tenemos el flag FSD activado estando OL (ON LINE, con corriente) se apague el servidor accidentalmente al reiniciar el demonio nut-server.
Si el SAI está en estado OB se mandan mensajes, se apaga un servidor auxiliar (con el que tenemos una relación de confianza para ejecutar comandos por ssh en él) y finalmente se apaga el servidor que ejecuta nut. Todo esto se hace a la media hora de estar funcionando con el SAI, por lo que da tiempo a cerrar todo tranquilamente ya que queda mas de la mitad de la batería.
4. Fuentes.
Acabo haciendo honores a las fuentes que he seguido para redactar esta entrada:
Se acerca la temporada de colas en el IES y desempolvamos nuestro sistema para dar gestionar las colas de espera para hacer algunas reformitas.
En su día creamos 3 scripts para incrementar, decrementar y poner a cero el contador de turnos. Hoy empezamos añadiendo un script nuevo que nos permitirá dar un valor concreto, que entrará como parámetro, al marcador:
# cat pon_turno.sh
#!/bin/bash
num=$1
test "$num" == "" && num="00"
servidor="172.X.Y.Z"
topic="numero"
if num=$(printf "%02d" $num 2> /dev/null)
then #Si $num no es un numero, falla el comando anterior
mosquitto_pub -t $topic -h $servidor -m "A-$num" -r
fi
Esto será útil si hay cualquier fallo que descontrole el marcador y necesitemos ir hasta un número directamente.
Para continuar, se me planteó la siguiente necesidad: controlar los turnos desde una aplicación normal y corriente como alternativa al método de la entrada anterior del blog (la cual usaba un ratón y triggerhappy como sistema para incrementar/decrementar el control del marcador de turnos). Podría escribir una aplicación de escritorio en Python y GTK, ya que con bash sería mas complicado, pero al final me he ido a lo mas sencillo y he optado por usar una aplicación web con Javascript+Mosquitto, usando la misma tecnología con que hice la pantalla que muestra el sistema de turnos del post anterior.
El aspecto de la aplicación será:
Al pulsar "Definir Turno" nos permitirán introducir un turno nuevo directamente:
Todo esto se implementa con una página HTML con mucho CSS y Javascript, ahí va:
Todos los ficheros necesarios ya los enlacé en entrada anterior del blog. Simplemente habría que añadir GestionTurnos.html en el mismo sitio web donde pusimos SuTurno.html
Al estar basada en Mosquitto la página web GestionTurnos.html se actualizará en tiempo real y si está abierta en varias ubicaciones (por ejemplo todos los PC de administración) cualquier cambio se propagará a todas los demás de forma inmediata.
Una vez la tenemos funcionando se me ocurre dar una vuelta de tuerca más y convertir la aplicación web en una aplicación independiente de escritorio. De esta manera correrá en una ventana autónoma del navegador que podrá minimizarse y maximizarse a voluntad y será mas sencilla de usar. Hay muchas herramientas para realizar esta conversión web->escritorio, pero me ha gustado por su sencillez Nativifier. Lo que haremos será:
# cat /etc/apt/sources.list.d/nodesource.list
deb https://deb.nodesource.com/node_0.10 trusty main
deb-src https://deb.nodesource.com/node_0.10 trusty main
# apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 1655A0AB68576280
# apt-get update
# apt-get install nodejs
# npm install nativefier -g
# nativefier -n "Sistema de Gestión de Turnos" http://172.X.Y.Z/turnos/GestionTurnos.html
Esto crea un directorio con un fichero ejecutable estándar de Linux que al lanzarlo abre la aplicación Web de Gestión de Turnos como si fuera una aplicación de escritorio. Bastará con poner un acceso directo en el escritorio del usuario y quedará todo simple y accesible.
Si queremos que la aplicación sea usada por todos los usuarios de la máquina lo mas sencillo será llevarla a /opt y dar permisos 777 a todo el directorio donde está.
Bueno, pues ya solo nos falta hacer algún día una aplicación para el móvil...
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:
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:
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:
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:
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):
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:
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
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).
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.
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.
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.
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:
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:
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"
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:
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.
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.