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

martes, 28 de noviembre de 2017

Reinicio periódico en DLink DIR-860L con dd-wrt

Es muy conveniente reiniciar algunos sistemas de forma periódica. En el caso de nuestros puntos de acceso DLink DIR-860L es casi obligatorio ya que cuanto mas tiempo pasan en funcionamiento mas empiezan a fallar ciertos aspectos, lo cual nos obliga al final a hacer un reset manual.

Mis compañeros Paco y Noemí me descubrieron que el propio dd-wrt incorpora un mecanismo de reinicio periódico, sin necesidad de configurar a mano crontab. Aunque se puede definir usando el interface web, buscando la opción "Administracion->Keep alive" entre sus pestañas nosotros lo vamos a hacer por comando. Consiste en entrar por ssh y ejecutar en cada punto de acceso los siguientes comandos:
nvram set schedule_enable=1
nvram set schedule_hour_time=2
nvram set schedule_weekdays=*
nvram set schedule_hours=7
nvram set schedule_minutes=0
nvram set schedule_time=3600
nvram set ntp_enable=1
nvram set ntp_server=..ip servidor centro..
nvram set ntp_mode=auto
nvram commit
reboot
Comentemos:
  • schedule_enable: puesto a 1 habilita el reinicio programado.
  • schedule_hour_time: puesto a 1 activa el reinicio cada X segundos, puesto a 2 el reinicio a dias/horas determinados.
  • schedule_weekdays, schedule_hours, schedule_minutes: días y hora donde se realiza el reinicio. En mi caso, todos los dias a las 7:00 de la mañana.
  • schedule_time: segundos entre reinicio si schedule_hour_time=1.
  • ntp_enable: puesto a 1 habilita la sincronización de hora por ntp.
  • ntp_mode: con valor auto se realiza una sincronización automática.
  • ntp_server: IP del servidor ntp de nuestra red. Normalmente es el servidor principal del centro.
El servidor ntp se configura para que el punto de acceso se ponga en hora y haga los reinicios en el momento correcto, ya que si no se piensa que estamos en 1970 y a una hora intempestiva del día. Una vez arrancado el punto de acceso tarda un rato en sincronizar la hora, parece ser que no le corre prisa eso, pero si somos pacientes al final coge la hora y fecha correcta.

Gracias a estos reinicios nuestros puntos de acceso serán mucho mas estables y se portarán mejor. Nada como un buen reinicio para limpiar un sistema.

martes, 14 de noviembre de 2017

Conectar por ssh/vnc al PC del profesor tras el punto de acceso DLink DIR-860L

En esta entrada anterior vimos como hacer NAT en el aula usando un punto de acceso DLink DIR-860L, de manera que los PC de alumnos y profesor quedaban en red privada dentro del rango 192.168.0.X.

El punto de acceso tenía dos direcciones: la 172.X.Y.Z (que sería la pública del centro) y la 192.168.0.254 (dentro de la red privada del aula), haciendo NAT entre ellas. Esto aísla por completo el aula de la red del centro pudiendo asegurar que el DLink realiza el NAT de una forma bastante más eficiente que los equipos HP que nos trajeron a los infolab.

El problema derivado es que no podemos conectar por ssh ni por vnc con el ordenador del profesor, que queda detrás del DLink. Esto causa bastante trastorno ya que es muy normal conectar para realizar diversas tareas de forma remota. Existe una vía indirecta para conectar por ssh, entrando primero en el DLink y luego desde alli haciendo ssh root@192.168.0.100, pero aparte de ser lento no podemos usar ssh -X para abrir aplicaciones gráficas sobre la conexión.

La solución está en configurar el port forwarding en el DLink para redigir determinadas conexiones a 172.X.Y.Z para que acaben en el 192.168.0.100 de la red privada. Es el famoso "abrir puertos" que hemos hecho todos en el router de casa para usar torrent o juegos.

El método paso a paso para abrir puertos en el entorno web de DD-WRT de nuestro punto de acceso DLink está descrito en este vídeo.

Para redirigir ssh he optado conectar el puerto 23 de la IP externa con el puerto 192.168.0.100:22, mediante la opción NAT-Qos -> Port Forwarding:


Uso el puerto 23 porque el puerto 22 está reservado para el servicio sshd del punto de acceso y no quiero perder la posibilidad de hacer ssh al DLink. Una vez aplicados los cambios, si desde cualquier punto de la red del centro hacemos:
$ ssh -X -p 23 root@172.X.Y.Z
conectaremos con el PC del profesor, saltando de forma transparente el DLink. Al usar "-X" tenemos la posibilidad de abrir aplicaciones gráficas.

Para redirigir vnc he usado la opción NAT-Qos -> Port Range Forwarding:


Pongo el rango de puertos 5900-5910 ya que vnc va usándolos de forma secuencial si hay varias sesiones vnc abiertas. En este caso el mapeo de los puertos es directo: el 5900 de fuera se conecta con el 5900 de dentro. Teniendo arrancado el servidor vnc en el PC del profesor (en mi caso lo arranco a mano cuando lo necesito, entrando antes por ssh) desde fuera haremos:
$ vinagre 172.X.Y.Z 
y entramos en el pc interno al aula.

Con esto tendremos acceso a esos PC igual al que tenemos a cualquier otro PC de profesor del centro.

martes, 7 de noviembre de 2017

Personalizando la pantalla de login de los portátiles de alumnos.

Como ya dijimos en la anterior entrada lo mas extendido es asignar cada portátil a un mismo alumno durante todo el curso.

Para poner las cosas sencillas ponemos una etiqueta adhesiva en la tapa o en el inferior con los datos del portátil y del alumno, pero esta etiqueta se puede quitar/caer y, por otro lado, no es infrecuente que algunos alumnos estén en la luna de Valencia y acaben confundiendo sus portátiles.

Una buena solución es que en la pantalla de login salga algo que identifique al alumno justo antes de poner sus credenciales: una foto, un texto con su nombre, etc. De esta manera se minimiza la posibilidad de coger otro portátil de forma accidental ya que se darán cuenta al meter las credenciales. Mi compañero Manu hizo la aplicación autolabel, que toma los datos del árbol ldap (en su árbol ldap hay campos que asocian portátil y alumno) y modifica el greeter del gdm3 (fichero /etc/gdm3/greeter.gsettings) para mostrar en él la foto y nombre del alumno.

Con xubuntu nos hemos cambiado a lightdm que desgraciadamente no tiene la versatilidad de gdm3 para poner imágenes y textos en la pantalla de login. Pero que no cunda el pánico: siempre podemos coger la imagen de fondo del greeter y manipularla con la utilidad convert para añadir la foto y nombre del alumno.

Para ello tengo un script que obtiene el login del alumno asociado al portátil, coge su foto y otros campos (tal como ya hicimos en la entrada anterior) y modifica nuestro fondo estándar de lightdm, almacenado en "/usr/share/xfce4/backdrops/fondo_1a.jpg".
# cat cambia_background_greeter.sh 

#!/bin/bash
#Curso 17-18-v1.
nombre_pc=$(/bin/hostname)
ldaphost=ldap
base=dc=instituto,dc=extremadura,dc=es
userbase=ou=People,$base
interno="cn=interno,dc=instituto,dc=extremadura,dc=es"
pwd_interno="mipwdinterno"
tmp="/tmp"
fondo_original="/usr/share/xfce4/backdrops/fondo_1a.jpg"
fondo_bak="/usr/share/xfce4/backdrops/fondo_1a_bak.jpg"
fichero="/root/scripts/asignaciones.txt"

test -e $fondo_bak || cp -f $fondo_original $fondo_bak

linea=$(/bin/grep -i -e "^${nombre_pc};" $fichero)
if [ -z $linea ] # no encontrado nombre.
then
  echo "ERROR: No encuentro portatil. Abortado"
  exit 1
fi

#Llegados aquí, en $linea tenemos nombre-pc;mac;usuario;password;grupo
usuario=$(echo $linea | /usr/bin/cut -d";" -f3)
pass=$(echo $linea | /usr/bin/cut -d";" -f4)
grupo=$(echo $linea | /usr/bin/cut -d";" -f5)
nombre=$(ldapsearch -w $pwd_interno  -D $interno -xLLL -t -h $ldaphost -b $userbase "(&(objectClass=posixAccount)(uid=$usuario))" | grep "^cn: ")
nombre=${nombre:4} # quitamos "cn: "

rm -f $tmp/ldapsearch-jpegPhoto-*
ldapsearch -w $pwd_interno  -D $interno -xLLL -T $tmp -t -h $ldaphost -b $userbase "(&(objectClass=posixAccount)(uid=$usuario))" jpegPhoto
if [ -e $tmp/ldapsearch-jpegPhoto-* ]; then
  mv -f $tmp/ldapsearch-jpegPhoto-* $tmp/.face 2> /dev/null
else
  cp -f /root/scripts/anonymous.jpg $tmp/.face 2> /dev/null # Foto genérica para alumnos sin foto.
fi
convert $fondo_bak  \( $tmp/.face -resize 200x200 \) -geometry +1700+50 -composite -matte $tmp/output.jpg
comando="text 20,300 \"Alumno: $usuario\"; text 20,340 \"${nombre}\"; text 20,380 \"Grupo: ${grupo}\""
convert $tmp/output.jpg  -pointsize 30 -fill yellow -gravity northeast -draw "$comando" $fondo_original
rm $tmp/.face
rm $tmp/output.jpg

exit 0
Recordemos que en pwd_interno debemos poner la contraseña que hayamos puesto a nuestro usuario "interno" de ldap. Todo esto se distribuye y ejecuta una vez más desde una tarea puppet:

class xubuntu_portatil {
  .....
  .....
  .....
  #Etiquetado fondo lightdm con datos alumno

  file {"/root/scripts/cambia_background_greeter.sh":
        owner=>root, group=>root, mode=>755,
        source=>"puppet:///modules/xubuntu_portatil/cambia_background_greeter.sh",
        notify => Exec["etiqueta-lightdm"],
  }

  file {"/root/scripts/anonymous.jpg":
        owner=>root, group=>root, mode=>755,
        source=>"puppet:///modules/xubuntu_portatil/anonymous.jpg",
        notify => Exec["etiqueta-lightdm"],
  }

  exec { "etiqueta-lightdm":
                        path => "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                        command => "/root/scripts/cambia_background_greeter.sh",
                        require => [File["/root/scripts/cambia_background_greeter.sh"],File["/root/scripts/anonymous.jpg"]],
                        refreshonly => true,
  }

  .....
  .....
  .....
}
El fichero anonymous.jpg es cualquier fichero con una foto genérica que queramos poner como imagen por defecto. Yo tengo una imagen tipo:


Tras ejecutarse el script al actualizar por puppet la pantalla de login del portátil quedaría tal que así:


El próximo año bastaría con cambiar el fichero asignaciones.txt distribuido en la tarea anterior y modificar el script un poco para que se baje y ejecute de nuevo.

Y con esto creo que acabo por ahora la serie de preparación de portátiles de alumnos.

Por último, no puedo dejar esto sin conmemorar que hoy es el centenario de la Revolución Rusa y nada mejor que una buena película sobre la gloriosa gesta del primer paseo espacial de Alexey Leonov para homenajearlo:


domingo, 5 de noviembre de 2017

Automatizando la configuración de portátiles de alumnos al inicio de cada curso.


Lo más común en nuestros centros es que los portátiles estén asignados durante todo el curso a un mismo alumno, que es responsable de su buen uso. Eso hace que cada año al comenzar el curso haya que realizar un proceso manual que comprende al menos los siguientes pasos:
  1. Cargar la imagen del sistema operativo en el portátil si fuere necesario, usando Clonezilla o DRBL.
  2. Limpiar datos del usuario anterior y actualizar el portátil.
  3. Copiar la configuración de la red wifi del aula donde va el portátil en el caso de que el portátil sólo vaya a usarse en una única estancia y con contraseña fija.
  4. Actualizar el nombre del portátil. Aquí tenemos 2 opciones: que el nombre coincida con el login del alumno o que el nombre del portátil sea independiente del mismo y permanezca invariable de un año a otro. Cada centro decide como gestionar la nomenclatura según su criterio.
  5. Cachear las credenciales del alumno que va a usar el portátil, para permitir que inicie sesión sin tener conexión a la red del centro.
El paso 1 ya hemos visto hasta la saciedad que puede hacerse de forma bastante automática y concurrente usando DRBL o Clonezilla.

El paso 2 ya contamos como realizarlo en la anterior entrada.

El paso 3 es sencillo: basta con copiar un fichero con la configuración a /etc/NetworkManager/system-connections/ de cada portátil. Ese fichero se saca conectando a la wifi con un portátil de forma manual y luego recuperando ese fichero de configuración para distribuirlo a los demás mediante puppet.

Veremos a continuación como automatizar lo más posible los pasos 4 y 5. Para ello necesitamos una manera de relacionar cada alumno con el portátil que tiene asignado y determinar el nombre del mismo, así como obtener mas información que pueda ser útil, como la contraseña que tendrá el usuario o el grupo al que pertenece.

Lo ideal sería tenerlo todo en una base de datos centralizada (ya sea una BBDD tradicional o en nuestro ldap) y consultar via un servicio web o similar, pero de momento no dispongo de dicho artefacto. Así que me he ido a lo más cutre: tengo un fichero de texto en formato .cvs con todos los datos que necesito. Dicho fichero lo copio via puppet y lo proceso en cada portátil. El formato del fichero es:
# cat asignaciones.txt 
porthp-o11;22:30:43:11:34:3A;aiglesiasz21;12433133;ESO3oA
porthp-o02;22:30:43:11:37:3C;rbarradop11;32212244;ESO3oB
......
Es un fichero con 5 columnas separadas por punto y coma: nombre del portátil, MAC de alguna tarjeta de red del portátil (normalmente ethX), nombre del alumno que lo tiene asignado, contraseña por defecto del alumno y grupo al que pertenece el mismo.

Al ser un .cvs es sencillo abrirlo en una aplicación de hoja de cálculo y rellenarlo de forma adecuada. Los datos de las MAC los podemos obtener de los facter almacenados en servidor:/var/lib/puppet/yaml/facts. Los datos de cada usuario se obtienen del fichero Alumnos.xml que descargamos desde Rayuela.

Este es el script que uso:
# cat cachea-credenciales.sh 
#!/bin/bash

fichero="/root/scripts/asignaciones.txt"  # fichero con las asignaciones de portatiles, con lineas csv en formato nombre-pc;mac;usuario;password;grupo. La mac puede ser "-"
                            # si el pc tiene nombre y se encuentra en el fichero, la mac es despreciada. En ese caso, el pc mantiene su nombre.
temporal="/tmp/macs_pc"
nombre_pc=$(/bin/hostname)
ldaphost=ldap
base=dc=instituto,dc=extremadura,dc=es
userbase=ou=People,$base
interno="cn=interno,dc=instituto,dc=extremadura,dc=es"
pwd_interno="mi_contrasena"

#Buscamos pc por nombre en fichero de asignaciones. 
#Nota: si queremos cambiar el nombre del pc en funcion de la mac habria que buscar aquí por mac primero y luego ajustar los nombres.
#Eso no lo hacemos, pero queda dicho.

linea=$(/bin/grep -i -e "^${nombre_pc};" $fichero)
if [ -z $linea ] # no encontrado nombre, buscamos por macs
then
  /sbin/ifconfig -a | /bin/grep HWa | tr -s ' ' | cut -f5 -d' ' | tr '[a-z]' '[A-Z]' | sort -u > $temporal # se cogen todas macs.
  macs_pc=$(/bin/cat $temporal)
  linea=$(/bin/grep -i -f $temporal $fichero)
  if [ -z $linea ]
  then 
     echo "ERROR: No encuentro las macs $macs_pc. Abortado"
     exit 1
  else
     #mac encontrada, hay que dar nombre al pc
     nombre_pc=$(echo $linea | /usr/bin/cut -d";" -f1)

     echo "127.0.0.1       localhost
127.0.1.1       $nombre_pc

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters" > /etc/hosts
     echo "$nombre_pc" >  /etc/hostname
     hostname -F /etc/hostname
  fi
fi

#Llegados aquí, en $linea tenemos nombre-pc;mac;usuario;password;grupo

usuario=$(echo $linea | /usr/bin/cut -d";" -f3)
pass=$(echo $linea | /usr/bin/cut -d";" -f4)
grupo=$(echo $linea | /usr/bin/cut -d";" -f5)

#Chequeamos credenciales por defecto del alumno  intentando acceder al campo privado employeeNumber
eNumber=$(ldapsearch  -w $pass -D "uid=$usuario,$userbase" -xLLL -t -h $ldaphost -b $userbase "(&(objectClass=posixAccount)(uid=$usuario))" employeeNumber | grep "^employeeNumber" | cut -d" " -f2)
if [ "$eNumber" != "" ]
then
   #Cachea credencial por defecto alumno
   /usr/sbin/cc_test -store any $usuario $pass 
   /usr/sbin/nss_updatedb ldap
else
   echo "WARNING: El alumno ha cambiado la contraseña, no se cachea."
fi

#Buscamos el homeDirectory del alumno en ldap
homeDirectory=$(ldapsearch -x -h $ldaphost -b $userbase "uid=$usuario" | grep "^homeDirectory" | cut -d" " -f2)
if [ "$homeDirectory" != "" ]
then
   #Si no existe se crea
   test -d $homeDirectory || /sbin/mkhomedir_helper $usuario
   #Y se baja la foto para guardarla en .face
   rm -f $homeDirectory/ldapsearch-jpegPhoto-*
   ldapsearch -w $pwd_interno  -D $interno -xLLL -T $homeDirectory -t -h $ldaphost -b $userbase "(&(objectClass=posixAccount)(uid=$usuario))" jpegPhoto
   if [ -e $homeDirectory/ldapsearch-jpegPhoto-* ]; then
          mv -f $homeDirectory/ldapsearch-jpegPhoto-* $homeDirectory/.face 2> /dev/null
          chown root  $homeDirectory/.face 2> /dev/null
          chmod 444 $homeDirectory/.face 2> /dev/null
   fi
fi

exit 0
Básicamente hace lo siguiente:
  • Obtenemos el nombre del portatil y lo buscamos en el fichero.
  • Si no lo encontramos, obtenemos su MAC y la buscamos. Si aparece la MAC, cogemos el nombre asociado y se lo damos al portátil.
  • Si no encontramos coincidencia en nombre ni MAC se acaba el script.
  • Cogemos el nombre de alumno, su clave y el grupo al que pertenece.
  • Verificamos contra ldap si el alumno mantiene esa clave y no la ha cambiado. Si es así la cacheamos.
  • Conseguimos en ldap su homeDirectory y lo creamos de forma local en el portátil usando mkhomedir_helper.
  • Por último, obtenemos de ldap su foto y la copiamos en el fichero .face de su home local. Es conveniente tenerla para algunas aplicaciones.
  • Para obtener la foto usamos el usuario "interno" que tiene definido nuestro arbol ldap. Este usuario tiene una clave en principio desconocida, pero la podemos cambiar nosotros mismos usando phpldapadmin y luego la ponemos a mano en el script, en la variable "pwd_interno".
A modo de sugerencia, otras cosas que no hace el script pero que sería interesante realizar:
  • Comprobar primero la MAC y ver si el nombre en el portátil coincide con el nombre en el fichero, renombrando en ese caso el portátil al del fichero.
  • Usar el grupo para otras tareas útiles, por ejemplo determinar y autoconfigurar la red wifi a la que se conectará.
Por último, distribuimos ambos ficheros desde nuestra tarea puppet favorita:
class xubuntu_portatil {
  ....
  ....
  file {"/root/scripts/asignaciones.txt":
        owner=>root, group=>root, mode=>500,
        source=>"puppet:///modules/xubuntu_portatil/asignaciones.txt",
  }


  file {"/root/scripts/cachea-credenciales.sh":
        owner=>root, group=>root, mode=>755,
        source=>"puppet:///modules/xubuntu_portatil/cachea-credenciales.sh",
  }
  ....
  ....
}
Podríamos automatizar también su ejecución, como lo tenemos hecho en el script de limpieza de credenciales, pero de momento prefiero lanzarla a mano en cada portátil mientras no adquiere mas rodaje. Ya habrá tiempo de hacerlo de forma desatendida en un futuro.

Todo esto es una mezcolanza de ideas tomadas en los últimos años de scripts que han hecho varios compañeros y han compartido conmigo. ¡Gracias Nando, Manu, Antonio Abasolo y seguramente alguno más!

martes, 31 de octubre de 2017

Limpieza de portátiles de alumnos a principio de curso.

A principio de curso siempre tenemos que preparar los portátiles asignados a los alumnos, empezando por hacer una limpieza general de los mismos. Con los años hemos ido automatizando esto lo más posible para evitar tener que repetir una serie de tareas portátil a portátil.

Aparte de ejecutar puppet y pkgsync para actualizar convenientemente los portátiles, es recomendable borrar las credenciales cacheadas de antiguos usuarios, sus homes y las conexiones wifi creadas en el pasado por los alumnos. Este sería el script a ejecutar al inicio de curso:
# cat limpia_credenciales.sh

#!/bin/bash
#Curso 17-18. Version v1.

#Limpia credenciales cacheadas
for i in $(cc_dump | awk ' {print $3} '); do  cc_test -update any $i -  ; done

#Limpia conexiones wifi antiguas
rm /etc/NetworkManager/system-connections/*

#Limpia homes antiguos
rm -rf /home/alumnos/*

exit 0
Para ejecutarlo la forma mas sencilla es usar unas reglas puppet que aplicaríamos a los portátiles. En mi caso tengo un módulo puppet "omnibús" llamado xubuntu_portatil donde tengo varias pequeñas tareas de este tipo.

El esquema es el típico de estos casos: si no existe o ha cambiado, copiamos el script al portátil y lo ejecutamos.
class xubuntu_portatil {
  
  .......
  .......
  #Limpieza de credenciales a inicio de curso. El script se ejecuta una vez. Si queremos que se ejecute de nuevo
  #hay que cambiar el contenido (p.ej. la versión)

  file {"/root/scripts":
     ensure => directory,
     before => File["/root/scripts/limpia-credenciales.sh"],
  }

  file {"/root/scripts/limpia-credenciales.sh":
        owner=>root, group=>root, mode=>755,
        source=>"puppet:///modules/xubuntu_portatil/limpia-credenciales.sh",
        notify => Exec["limpia-credenciales"],
  }

  exec { "limpia-credenciales":
                        path => "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                        command => "/root/scripts/limpia-credenciales.sh",
                        require => File["/root/scripts/limpia-credenciales.sh"],
                        refreshonly => true,
  }
  .......
  .......

}
Cada vez que queramos hacer limpieza basta con cambiar algo (basta, por ejemplo, con cambiar la fecha o nº de versión de v1 a v2) en el script almacenado en el directorio "files" de nuestro módulo xubuntu_portatil y se copiará de nuevo y ejecutará.

domingo, 22 de octubre de 2017

rsync con sistemas de ficheros ntfs

Estoy haciendo backups de todas mis imágenes clonezilla a una máquina con partición de destino ntfs y me encuentro con que rsync copia de nuevo muchos ficheros que no han variado cada vez que lo lanzo.

Lo que hace rsync (a no ser que le pongamos el parámetro --checksum) es comparar la fecha de modificación y tamaño de cada fichero en origen y destino y si difiere algo sincroniza de nuevo el fichero. Eso en sistemas ext2/3/4 funciona sin problemas con:
# rsync -avP root@ip-origen:/mnt/partimag/* /mnt/partimag
Pero si uno o ambos sistemas de ficheros es ntfs (y seguramente también fat) no funciona. La causa es que la precisión o el formato de las fechas en ntfs es distinto al de ext2/3/4 y rsync se muestra confundido, considerando fechas distintas las que no lo son. La solución consiste en proporcionar una ventana de error de varios segundos para permitir conciliar bien las fechas:
# rsync -avP --modify-window=5 root@ip-origen:/mnt/partimag/*  /mnt/partimag
Con el ejemplo anterior doy 5 segundos de margen de error al comparar 2 fechas de modificación y tomar la decisión de que han cambiado. Por supuesto eso se puede afinar lo que haga falta en función de cada caso, aunque a mi con 5 segundos me ha ido bien.

lunes, 16 de octubre de 2017

En busca del musthave mínimo.

Como estos días he estado enredando con pkgsync no he podido evitar darme cuenta de que el musthave que tengo en todos los pc es bastante tocho. En su mayoría han sido generados con el script /root/scripts/generar_musthave.sh y por lo que veo tienen mucha redundancia.

Por ejemplo, tener en el musthave los paquetes libreoffice y libreoffice-writer es redundante. Las dependencias del primero implican tener instalado el segundo, por que solo con tener el primero en musthave es suficiente. Sobre las librerías (paquetes lib*) mejor ni hablar: casi todas se instalan de forma automática al cumplir las dependencias de otro paquete de rango superior.

El hecho de tener en musthave solo los paquetes importantes, y no sus dependencias, lo hacen mas manejable y menos susceptible a caer en el "pkgsync installation loop" (esté término me lo acabo de inventar). Este "loop" pasa cuando tenemos en el musthave paquetes que son excluyentes entre si y pkgsync resuelve esta situación esquizofrénica instalando y quitando grupos de paquetes en cada llamada de forma alternativa. Eso no debe ser así, ya que pkgsync debe comportarse de forma idempotente: si no tocamos ningún fichero (mayhave/musthave/maynothave/...) todas las llamadas de pkgsync deben quedar el sistema de paquetes como estaba, invariante.

Por esto y porque me apetecía me puse a mirar como reducir el tamaño del musthave para que esté lo mas puro y mínimo posible. Vamos a ver poco a poco lo que he encontrado:

Primero sacamos una lista ordenada con los paquetes instalados de forma no automática (de esta forma nos libramos de los paquetes tipo librería y otros dependientes). Es lo que se llama paquetes explícitos:
# paquetes_explicitos=$(aptitude search '~i !~M' -F '%p' --disable-columns | sort -u)
De estos paquetes los habrá que se han instalado desde /etc/pkgsync/musthave, también estarán los que se hayan instalado desde /etc/pkgsync/musthave.d por tareas independientes nuestras y, por último, los que se hayan instalado a mano y puesto en /etc/pkgsyc/mayhave para no ser desinstalados. Solo nos interesan los primeros (ya que lo que queremos es aligerar el etc/pkgsync/musthave inicial).
for i in $paquetes_explicitos
do
   echo -n "Paquete $i"
   if grep $i /etc/pkgsync/musthave > /dev/null
   then
        echo " ->instalado por musthave"
        echo $i >> musthave.new        
   else
      if grep $i /etc/pkgsync/mayhave > /dev/null
      then
          echo "  ->instalado por mayhave"
      else
          echo "  ->instalado por musthave.d"
      fi
   fi
done
sort -u -o musthave.new musthave.new
A la salida tenemos en musthave.new los paquetes explícitos que están en el /etc/pkgsync/musthave original. Con esto tenemos una selección bastante buena de paquetes, pero no es suficiente. Si miramos detenidamente en el musthave.new vemos que sigue habiendo redundancias. Hay que ir mas allá y limpiar todos los paquetes de musthave.new que dependan de otros paquetes que estén en ese mismo fichero.

Con el siguiente bucle que recorre musthave.new voy metiendo en musthave.deps todas las dependencias de cada paquete. Para ello uso el comando apt-rdepends (que saca las dependencias y sugerencias de un paquete), aplico un par de filtros para quedarme sólo con las dependencias y si aparece el propio paquete entre sus dependencias lo ignoro (por extraño que parezca, a veces sucede). Por último ordenamos la lista de paquetes dependientes y quitamos los repetidos usando "sort -u":
for i in $(cat musthave.new)
do
   #echo "Dependencias de $i"
   apt-rdepends $i |grep Depends: | awk ' { print $2 } ' | sed "/^${i}$/d" >> musthave.deps
done
sort -u -o musthave.deps musthave.deps
Una vez hecho esto, quitamos de musthave.new todos los paquetes que también estén en musthave.deps mediante "comm -23", borrando los paquetes redundantes y dejando el resultado en musthave.final:
comm -23 musthave.new  musthave.deps  > musthave.final
Todo el script junto queda:
# cat musthave-minimo
#!/bin/bash

if [ ! -f /usr/bin/apt-rdepends ]
then
    echo "Instalando apt-rdepends"
    apt-get install apt-rdepends
fi

cp /dev/null musthave.new
cp /dev/null musthave.deps

paquetes_explicitos=$(aptitude search '~i !~M' -F '%p' --disable-columns | sort -u)
for i in $paquetes_explicitos
do
   echo -n "Paquete $i"
   if grep $i /etc/pkgsync/musthave > /dev/null
   then
        echo " ->instalado por musthave"
        echo $i >> musthave.new        
   else
      if grep $i /etc/pkgsync/mayhave > /dev/null
      then
          echo "  ->instalado por mayhave"
      else
          echo "  ->instalado por musthave.d"
      fi
   fi
done
sort -u -o musthave.new musthave.new

num=1
total=$(wc -l  musthave.new)
for i in $(cat musthave.new)
do
   echo "Dependencias de $i: $num/$total"
   ((num++))
   apt-rdepends $i |grep Depends: | awk ' { print $2 } ' | sed "/^${i}$/d" >> musthave.deps 
done
sort -u -o musthave.deps musthave.deps
comm -23 musthave.new  musthave.deps  > musthave.final

exit 0
Una vez obtenido el musthave.final podemos compararlo con el musthave inicial y con mushave.new usando "wc -l". Veremos que el número de paquetes se ha reducido considerablemente. Esto es un ejemplo sobre un Ubuntu con la imagen LTSP:
# wc -l musthave*
 1837 musthave.deps
  174 musthave.final
 1285 musthave
  501 musthave.new
Como vemos pasamos de 1285 paquetes en el musthave generado con el script generar_musthave.sh a 174 en musthave.final, tras realizar las sucesivas purgas de paquetes dependientes.

Antes de aplicar musthave.final de forma general es conveniente hacer una copia de seguridad /etc/pkgsync/musthave, sobrescribir musthave.final sobre él y ejecutar pkgsync en modo simulación (no hace nada de verdad, simplemente te dice que ficheros quitaría y que ficheros instalaría), para calibrar si es inofensivo.
# cp /etc/pkgsync/musthave /etc/pkgsync/musthave.backup
# cp musthave.final /etc/pkgsync/musthave
# pkgsync -s
Normalmente nos dirá que quiere quitar algunos paquete secundarios raros que no parecen tener mayor importancia. Aquí entra en juego la pericia de cada cual a la hora de evaluar el riesgo de dejarle que quite esos paquetes, pero por mi experiencia y tras investigar el contenido los paquetes propuestos puedo decir que todas las veces me han salido paquetes anodinos, que ni sé que hacen ahí ni los voy a echar de menos cuando se vayan.

Una vez seguros de lo que queremos hacer cogemos aire, nos encomendamos a Odín y ejecutamos "pkgsync" sin mirar atrás. En el peor de los casos, siempre podemos volver a cargar la imagen con clonezilla ;-).

viernes, 13 de octubre de 2017

Cómo montar el pkgsync con control compartido usando puppet.

Cada vez que preparo un tipo nuevo de equipo y tengo que meterle pkgsync para mantener la coherencia de los paquetes de forma centralizada me toca re-estudiarme como está montado. Esta vez voy a apuntarlo aquí a modo de guía.

1. Cómo funciona el pkgsync en máquinas clientes.

Gracias a Esteban tenemos un pkgsync cada vez mas potente y versátil. En los repositorios tenemos la version 1.39:
# apt-cache policy pkgsync
pkgsync:
  Instalados: 1.39
  Candidato:  1.39
  Tabla de versión:
 *** 1.39 0
        500 http://linex.educarex.es/ubuntu/trusty/ trusty/linex amd64 Packages
        500 http://servidor/html/linex2/ubuntu/trusty/ trusty/linex amd64 Packages
        100 /var/lib/dpkg/status
        ....
Hace años que partimos de un pkgsync primitivo basado en solo 3 ficheros (/etc/pkgsync/mayhave, maynothave y musthave) que nos daba muchos problemas de competencia entre lo que nos imponían desde Mérida y lo que queríamos tener cada uno en nuestro centro (¿quién manda si hay un único mayhave?).

Gracias a las mejoras de Esteban hemos evolucionado a un sistema de soberanía compartida, donde hay una parte del mayhave (y compañía) controlada por Mérida y otra controlada por nosotros.

Por ello ahora tenemos tres orígenes de ficheros que se fusionan al ejecutar pkgsync en un único /etc/pkgsync/mayhave.all, el cual toma la función que tenía el antiguo y solitario /etc/pkgsync/mayhave. Estos 3 orígenes son:

  • /etc/pkgsync/mayhave: es controlado por Mérida mediante diversas tareas puestas en nuestro servidor puppet. Si lo modificamos será sobreescrito desde el Puppet Master of Our Universe de la Consejería.
  • /etc/pkgsync/mayhave.ies: es controlado por nosotros en nuestro servidor puppet. Para ello debemos tener una tarea hecha que lo controle.
  • /etc/pkgsync/mayhave.d/*: es como mayhave.ies, pero en este directorio podemos poner varios ficheros que se fusionarán con el resto. Es muy cómodo para hacer grupos de paquetes personalizados según el tipo de equipo (por ejemplo /etc/pkgsync/mayhave.d/mayhave.multimedia y poner dentro una lista de paquetes relacionados con multimedia). También debemos tener una tarea hecha por nosotros que controle estos ficheros.

Of course, esto relatado del mayhave se aplica de forma idéntica para musthave y maynothave.

2. Cómo se distribuyen los ficheros de pkgsync oficiales desde el servidor puppet.

Para evitar tener que ir equipo a equipo, los ficheros vistos en el apartado anterior tienen que controlarse desde el servidor puppet del centro. Hemos convenido en que los ficheros musthave/mayhave/maynothave son controlados desde Mérida por su puppet, mientras que los musthave.ies/mayhave.ies/maynothave.ies y los musthave.d/mayhave.d/maynothave.d están controlados por nosotros por nuestro puppet.

Los controlados por el servidor de la Consejería en Mérida se guardan en la ruta /etc/puppet/files/xubuntu del servidor principal del centro. Si vamos allí, veremos al menos estos ficheros:
mayhave.siatic.i386
musthave.hp360
musthave.infolab
musthave.siatic
musthave.siatic.i386
Para saber que se hace con ellos, busco en las tareas puppet:
root@servidor:/etc/puppet# grep -ir puppetinstituto/files/xubuntu/mayhave * 
manifests/classes/xubuntu/siatic.pp:        source => "puppet://puppetinstituto/files/xubuntu/mayhave.siatic.i386",

root@servidor:/etc/puppet# grep -ir puppetinstituto/files/xubuntu/musthave * 
manifests/classes/xubuntu/notebookHP.pp:        source => "puppet://puppetinstituto/files/xubuntu/musthave.hp360",
manifests/classes/xubuntu/siatic.pp:        source => "puppet://puppetinstituto/files/xubuntu/musthave.siatic.i386",
manifests/classes/xubuntu/infolab.pp:#        source => "puppet://puppetinstituto/files/xubuntu/musthave.infolab",
De lo visto podemos decir que:
  • musthave.hp360: es el musthave que se copia para tablets-portátiles hp360.
  • musthave.infolab: es el musthave para infolabs. Lo cierto es que a día de hoy no se usa, se comentó su inserción por un problema con las tarjetas nvidia y así permanece.
  • mayhave.siatic.i386, musthave.siatic.i386: son el mayhave/musthave que se copia a las Siatic con sistema de 64bits.
  • musthave.siatic: ya no se usa. En su día era el oficial de los siatics, pero había paquetes de xserver que daban problemas y se dejó de insertar.

Como vemos, no hay musthaves/mayhaves/maynothave oficiales para equipos ltsp, workstations, portátiles distintos a los hp360 ni para siatics de 64bits. Se entiende que todos estos equipos tienen un /etc/pkgsync/musthave que viene de serie en su respectiva imagen y de momento la Sección no contempla modificarlos por puppet ya que no hay tarea oficial que se ocupe de actualizarlos.

En el caso de las siatic 64bits ni siquiera traen un musthave inicialmente (lo cual hace que pkgsync no funcione ya que requiere de su existencia para trabajar) y si lo queremos debemos generarlo con el script que aparece en la imagen llamado /root/Primer_arranque/generar_musthave.sh (el cual también es una creación de Esteban).

Por lo general tampoco hay mayhaves y maynothave oficiales para ningún equipo, ya que de momento no ha surgido la necesidad de tenerlos de forma general en todos los centros.

3. Cómo distribuyo los ficheros de pkgsync particulares desde el servidor puppet.

Hasta aquí hemos visto la infraestructura común, ahora veremos como controlar por nuestra parte los mayhave/musthave/maynothave que son de nuestra competencia. Nada de esto lo tenemos por defecto en el servidor del centro y por tanto nos toca montar por nuestra cuenta el módulo puppet y los ficheros que distribuye.

En primer lugar aclarar los musthave.ies/mayhave.ies/maynothave.ies no los uso. Tuvieron su momento cuando teníamos Debian Wheezy pero ahora preferimos la solución mas elegante basada en los ficheros fragmentados a través de musthave.d/mayhave.d/maynothave.d. Si lo montamos bien, podremos tener un musthave general, que se aplica a todos los equipos, y un musthave por cada tipo-use2 de equipo.

En mi caso, en /etc/puppet/files/xubuntu tengo esta estructura de directorios creada:
├── mayhave.d
│   ├── mayhave.infolab
│   ├── mayhave.infolab.profesor
│   ├── mayhave.ltsp.profesor
│   ├── mayhave.notebookHP
│   ├── mayhave.portatil-alumno
│   ├── mayhave.siatic
│   ├── mayhave.workstation
│   ├── mayhave.workstation-i386
│   └── mayhave.xubuntu
├── maynothave.d
│   ├── maynothave.infolab
│   ├── maynothave.infolab.profesor
│   ├── maynothave.ltsp.profesor
│   ├── maynothave.notebookHP
│   ├── maynothave.portatil-alumno
│   ├── maynothave.siatic
│   ├── maynothave.workstation
│   ├── maynothave.workstation-i386
│   └── maynothave.xubuntu
└── musthave.d
    ├── musthave.infolab
    ├── musthave.infolab.profesor
    ├── musthave.ltsp.profesor
    ├── musthave.notebookHP
    ├── musthave.portatil-alumno
    ├── musthave.siatic
    ├── musthave.workstation
    ├── musthave.workstation-i386
    └── musthave.xubuntu
Los ficheros .xubuntu se copian a todo los equipos con ubuntu y los otros según los facter tipo (siatic, infolab, ltsp, workstation, etc) y use2 (profesor/alumno). Para ello uso la siguiente clase puppet basada en la original que compartieron mis compañeros del IES Téllez hace ya tiempo:
# cat /etc/puppet/modules/xubuntu_pkgsync/manifests/init.pp 

#Clase para control de los ficheros básicos para pkgsync de siatic, infolab y notebookHP
import "/etc/puppet/defines/*.pp"

class  xubuntu_pkgsync {

        case $use2 {
                "profesor":  { $esprofe=".profesor" }
                default: { $esprofe = "" }
        }

        #====================================================================================================================
        #Ficheros dependientes del tipo: Se pone un mayhave, musthave, maynothave personalizado en función del tipo y use2 (si es profesor) 

        case $tipo {

                "siatic", "infolab", "notebookHP", "ltsp", "workstation","portatil-alumno", "workstation-i386": {  
                        file { "mayhave.instituto":
                         path => "/etc/pkgsync/mayhave.d/mayhave.$tipo",
                         owner => root, group => root, mode => 644, 
                         source => "puppet:///files/xubuntu/mayhave.d/mayhave.${tipo}${esprofe}",
                         ensure => file,
                        }

                        file { "maynothave.instituto": 
                         path => "/etc/pkgsync/maynothave.d/maynothave.$tipo",
                         owner => root, group => root, mode => 644,
                         source => "puppet:///files/xubuntu/maynothave.d/maynothave.${tipo}${esprofe}",
                         ensure => file,
                        }

                        file { "musthave.instituto": 
                         path => "/etc/pkgsync/musthave.d/musthave.$tipo",
                         owner => root, group => root, mode => 644,
                         source => "puppet:///files/xubuntu/musthave.d/musthave.${tipo}${esprofe}",
                         ensure => file,
                        }
                }
                default: { }

        }

        #====================================================================================================================
        #Musthaves/maynothave/mayhave globales para todos los xubuntus controlados por mi

        # musthave global para todos los xubuntu
        file { "musthave.xubuntu":
                path => "/etc/pkgsync/musthave.d/musthave.xubuntu",
                owner => root, group => root, mode => 644,
                source => "puppet:///files/xubuntu/musthave.d/musthave.xubuntu",
                ensure => file,
        }

        # mayhave global para todos los xubuntu
                file { "mayhave.xubuntu":
                path => "/etc/pkgsync/mayhave.d/mayhave.xubuntu",
                owner => root, group => root, mode => 644,
                source => "puppet:///files/xubuntu/mayhave.d/mayhave.xubuntu",
                ensure => file,
        }

        # maynothave global para todos los xubuntu
        file { "maynothave.xubuntu":
                path => "/etc/pkgsync/maynothave.d/maynothave.xubuntu",
                owner => root, group => root, mode => 644,
                source => "puppet:///files/xubuntu/maynothave.d/maynothave.xubuntu",
                ensure => file,
        } 

        #====================================================================================================================
        #Ficheros mayhave/maynothave principales vacios por defecto si no existen.
        #El musthave debe ser creado por el administrador a mano. No se crea por defecto por su peligrosidad.

        # Por si no existen los ficheros, los creamos inicialmente a vacíos
        file { "mayhave.inicial": 
                path => "/etc/pkgsync/mayhave",
                owner => root, group => root, mode => 644,
                ensure => file,
        }

        file { "maynothave.inicial": 
                path => "/etc/pkgsync/maynothave",
                owner => root, group => root, mode => 644,
                ensure => file,
        }

        #El musthave no se crea por precaucion. Si existe el pkgsync se ejecutaría y puede destrozar el sistema de paquetes.
        #   cada /etc/pkgsync/musthave debe ser creado a mano por el administrador. Si no existe, pkgsync se aborta.

}
Y así es como lo tengo montado, utilizando los facter tipo y use2 para colocar los ficheros en las máquinas correspondientes. Los compañeros de Mérida tienen sus ficheros y yo tengo los míos.

Si quiero aplicar un paquete a todos los Ubuntu lo meto en el fichero *.xubuntu correspondiente. Si quiero aplicarlo a un tipo concreto (por ejemplo en los workstation de 64bits), lo meto en el fichero *.workstation correspondiente. En la siguiente ejecución de puppet en el cliente se copiarán los ficheros desde servidor:/etc/puppet/files/xubuntu y en la posterior ejecución de pkgsync se sincronizarán los paquetes de acuerdo con lo ordenado.

Como se ve, es una solución elegante que permite que trabajar colaborativamente sin machacarnos entre nosotros. Parlem.

jueves, 28 de septiembre de 2017

Más Flash en los libros digitales: Editorial Santillana.

Ya hablamos del Flash en los libros digitales de Oxford. Esta semana me ha tocado lidiar con los libros digitales de francés de la Editorial Santillana: Parachute 1/2 y Lycée A1. Como no podía ser menos, Santillana (que viene a ser el brazo armado en educación del grupo Prisa - comentario a mala baba) también ha apostado por una novedosa tecnología de los 90 basada en Flash para sus libros.

Me llegan varios CD cuyo contenido es:
-rwxrwxr-x 1 root root 11183588 sep 26 10:50 a.out
-rw-r--r-- 1 root root       83 sep 26 10:21 autorun.inf
-rw-r--r-- 1 root root   292782 sep 26 10:21 browser.swf
drwxr-sr-x 4 root root    53248 sep 26 10:21 contenido
drwxr-sr-x 2 root root    36864 sep 26 10:21 curso
-rw-r--r-- 1 root root     1214 sep 26 10:21 exeBrowser.htm
-rwxr-xr-x 1 root root 11476637 sep 26 10:21 exeLinux
drwxr-sr-x 3 root root     4096 sep 26 10:21 exeMac.app
-rw-r--r-- 1 root root  5536668 sep 26 10:21 exeWin.exe
-rw-r--r-- 1 root root     1201 sep 26 10:21 lisez-moi.txt
drwxr-sr-x 2 root root     4096 sep 26 10:21 modulos
drwxr-sr-x 2 root root     4096 sep 26 10:21 recursos
drwxr-sr-x 2 root root     4096 sep 26 10:21 rr_moved
En negrita pongo lo interesante. Hay 4 opciones para lanzar la aplicación: exeLinux (para Linux), exeMac.app (para OSX), exeWin.exe (para Windows) y exeBrowser.htm (para navegadores web).

Después de copiar todo a una carpeta compartida de red (/home/..../dpto/Frances/Parachute_1) intento ejecutarlo de la forma normal, lanzando ./exeLinux. En un sistema de 32 bits se abre sin mayor problema y se ejecuta, pero en un sistema de 64 bits (y son la mayoría en nuestra red) sale esta pantalla en blanco:


Además, para ejecutarlo en 64 bits es necesario instalar antes el paquete libnss3:i386. Está claro que al ejecutable (con "file exeLinux" vemos que es de 32 bits) no le gusta nuestro sistema de 64 bits. Estuve investigando un rato si faltaba alguna librería de 32 bits en alguna ruta concreta o algo similar pero no encontré ninguna pista que me llevase a solucionarlo.

Un compañero me dijo que podía ejecutar la versión exeWin.exe mediante wine (simplemente haciendo wine /home/..../dpto/Frances/Parachute_1/exeWin.exe), ya que al parecer por esa vía funciona. Si no queda otra salida no me importa usar el maravilloso wine, pero prefiero probar otras opciones antes.

La única opción que me quedaba era la opción web, que se supone que es independiente del sistema operativo y de la arquitectura de 32/64 bits de éste. Con:
# firefox /home/..../dpto/Frances/Parachute_1/exeBrowser.htm
Se abre el navegador y se carga Flash, pero otra vez se muestra la página en blanco. Repasando notas vi el epílogo de esta entrada, en la cual comento que para ejecutar Flash con ficheros locales hay que dar permisos de forma explícita en dichas carpetas en la configuración de Flash Player.

Ya sabemos que Flash lleva dos o tres lustros teniendo problemas de seguridad y al final deben haber optado por la misma solución que Microsoft: si no podemos hacer un artefacto seguro al menos lo haremos paranoico.

¿Cómo configuramos esto?. Pues abriendo en un navegador Firefox la URL:
https://www.macromedia.com/support/documentation/es/flashplayer/help/settings_manager04.html
La cual nos carga una aplicación web que permite cambiar la configuración del Flash local de nuestro PC. Es un sistema raro de configuración pero así es como hacen las cosas los de Flash. Una vez allí, tal como contamos en la entrada anterior hacemos:

  • Primero, nos aseguramos de estar la pestaña en "Parámetros de seguridad global".
  • Marcamos "Permitir siempre".
  • Pinchamos en Editar--> Agregar--> Buscar carpeta. Le damos la ruta donde está instalado el Parachute y elegimos la carpeta. En mi caso la ruta es "/home/..../dpto/Frances).


Con esto ya podemos abrir la aplicación por web y ver que carga y ejecuta sin problema, ya que Flash tiene permiso para acceder a la ruta local donde está ubicada. Para facilitar el trabajo al usuario pongo este acceso directo en su escritorio:
# cat Parachute_1.desktop 

#!/usr/bin/env xdg-open

[Desktop Entry]
Name=Parachute 1
Version=4.1.0.0
Type=Application
Terminal=false
StartupNotify=true
Exec=firefox /home/.../dpto/Frances/ParaChute1/exeBrowser.htm
Categories=Education
Icon=/home/.../dpto/Frances/ParaChute1/recursos/intro01.jpg

Usándolo lanzamos el Firefox con la página local y con Flash ya configurado para confiar en dicha ubicación. Ahora si funciona tanto en 32 como en 64 bits.

Ya llegados aquí, estaba intrigado por averiguar dónde guarda Flash esta configuración que se edita de una manera tan rara con la URL externa https://www.macromedia.com/support/documentation/es/flashplayer/help/settings_manager04.html. No está muy documentado, pero la ruta donde se guarda esta configuración es:
~/.macromedia/Flash_Player/macromedia.com/support/flashplayer/sys/settings.sol
El fichero settings.sol está en un formato binario propio de Flash, aunque podemos husmear por encima usando la utilidad strings (ya que cat muestra un galimatías ASCII):
# strings settings.sol
Si queremos editar dicho fichero existen también herramientas que permiten leer un fichero .sol y editarlo, mirar dentro y exportarlo/importarlo a un .json. Una de ellas es Minerva, una aplicación online hecha en Flash que pinta así:


Ya para acabar, si queremos propagar esta configuración guardada de Flash a más usuarios simplemente hay que copiar el fichero settings.sol en la ruta indicada en todos sus homes, sin necesidad de ir configurando manualmente uno a uno. Hasta me ha resultado más cómodo comprimir el directorio ~/.macromedia en un .tar.gz y descomprimirlo tal cual en cada home, de tal forma que se crea el árbol de directorios de .macromedia de forma completa.

Bueno, pues hasta aquí hemos llegado con esto. Nos vemos en la siguiente aventura.

domingo, 10 de septiembre de 2017

Activar un usuario de Windows deshabilitado usando chntpw

Por imperativo legal he tenido que instalar un Windows 7 en una máquina algo antigua. Durante la instalación te pide un nombre de usuario que convertirá en el administrador de la máquina y será con el que por defecto se trabajará. El usuario por defecto es administrador, que te voy a contar...

Bueno, pues despues de hacer esto lo primero es despojar a ese usuario de trabajo de sus permisos de administrador, sacándole del grupo de "Administradores". Tras eso, en dicho grupo solo permanece el usuario "Administrador" que es creado de forma silenciosa durante la instalación. También hay que cambiar la contraseña al usuario "Administrador" por la que queramos que tenga.

Tras esto reiniciamos, vamos a la pantalla de login y vemos ambos usuarios. Pero si intentas acceder con el usuario Administrador te dice que "está deshabilitado". Agarrate: el Windows 7 te permite quedar el sistema sin un administrador válido sin avisarte de ello. ¿Ahora cómo habilito el usuario?.

Bueno, pues la solución está en arrancar con un CD/USB Live de Linux que tenga la herramienta chntpw, ya sea el CD propio o alguno que lo contenga (tipo SystemRescueCD o Ubuntu). Una vez arrancado, montamos la particion de Windows en /mnt (o equivalente) con:
# mount /dev/sda2 /mnt
Normalmente el sistema Windows a partir de su versión 7 está en la partición sda2 o sda3, siendo la sda1 una pequeña partición reservada para hacer el mal a través de UEFI o similar.

Una vez montada, hacemos una copia de seguridad del fichero de configuración de usarios (por si metemos la pata poder restaurar):
# cd /mnt/WINDOWS/System32/config
# cp SAM SAM.backup
Avisamos que alguno de los nombres anteriores podría estar en mayúscula/minúscula, en función del Windows usado.

Una vez hecha la copia de seguridad miramos el fichero con chntpw:
# chntpw /mnt/WINDOWS/System32/config/SAM
chntpw version 0.99.6 110511 , (c) Petter N Hagen

Hive  name (from header): <\SystemRoot\System32\Config\SAM>
ROOT KEY at offset: 0x001020 * Subkey indexing type is: 686c 
File size 65536 [10000] bytes, containing 5 pages (+ 1 headerpage)
Used for data: 298/27544 blocks/bytes, unused: 42/9160 blocks/bytes.


* SAM policy limits:
Failed logins before lockout is: 0
Minimum password length        : 0
Password history count         : 0
| RID -|---------- Username ------------| Admin? |- Lock? --|
| 01f4 | Administrador                  | ADMIN  | dis/lock |
| 01f7 | DefaultAccount                 |        | dis/lock |
| 01f5 | Invitado                       |        | dis/lock |
| 03ea | Usuario                        |        | *BLANK*  |
...
...
Como se ve, el usario Administrador está bloqueado. Para cambiar esa situación (o para borrar la contraseña si no la conocemos o la hemos olvidado), usamos el parámetro "-i" (pongo en negrita la parte interactiva):
# chntpw +i /mnt/WINDOWS/System32/config/SAM
chntpw version 0.99.6 110511 , (c) Petter N Hagen
Hive  name (from header): <\SystemRoot\System32\Config\SAM>
ROOT KEY at offset: 0x001020 * Subkey indexing type is: 686c 
File size 65536 [10000] bytes, containing 5 pages (+ 1 headerpage)
Used for data: 298/27544 blocks/bytes, unused: 42/9160 blocks/bytes.

* SAM policy limits:
Failed logins before lockout is: 0
Minimum password length        : 0
Password history count         : 0

<>========<> chntpw Main Interactive Menu <>========<>

Loaded hives: 

  1 - Edit user data and passwords
      - - -
  9 - Registry editor, now with full write support!
  q - Quit (you will be asked if there is something to save)

What to do? [1] -> 1

===== chntpw Edit User Info & Passwords ====

| RID -|---------- Username ------------| Admin? |- Lock? --|
| 01f4 | Administrador                  | ADMIN  | dis/lock |
| 01f7 | DefaultAccount                 |        | dis/lock |
| 01f5 | Invitado                       |        | dis/lock |
| 03ea | Usuario                        |        | *BLANK*  |

Select: ! - quit, . - list users, 0x - User with RID (hex)
or simply enter the username to change: [Administrador] ---pulso Enter---

RID     : 0500 [01f4]
Username: Administrador
fullname: 
comment : Cuenta integrada para la administracion del equipo o dominio
homedir : 

User is member of 1 groups:
00000220 = Administradores (which has 2 members)

Account bits: 0x0211 =
[X] Disabled        | [ ] Homedir req.    | [ ] Passwd not req. | 
[ ] Temp. duplicate | [X] Normal account  | [ ] NMS account     | 
[ ] Domain trust ac | [ ] Wks trust act.  | [ ] Srv trust act   | 
[X] Pwd don't expir | [ ] Auto lockout    | [ ] (unknown 0x08)  | 
[ ] (unknown 0x10)  | [ ] (unknown 0x20)  | [ ] (unknown 0x40)  | 

Failed login count: 0, while max tries is: 0
Total  login count: 1

- - - - User Edit Menu:
 1 - Clear (blank) user password
 2 - Edit (set new) user password (careful with this on XP or Vista)
 3 - Promote user (make user an administrator)
 4 - Unlock and enable user account [probably locked now]
 q - Quit editing user, back to user select
Select: [q] > 4
Unlocked!

Select: ! - quit, . - list users, 0x - User with RID (hex)
or simply enter the username to change: [Administrador] !

<>========<> chntpw Main Interactive Menu <>========<>

Loaded hives: 

  1 - Edit user data and passwords
      - - -
  9 - Registry editor, now with full write support!
  q - Quit (you will be asked if there is something to save)


What to do? [1] -> q

Hives that have changed:
 #  Name
 0  
Write hive files? (y/n) [n] : y
 0   - OK
Y ya podemos ver que está desbloqueado:
# chntpw /mnt/WINDOWS/System32/config/SAM
chntpw version 0.99.6 110511 , (c) Petter N Hagen

Hive  name (from header): <\SystemRoot\System32\Config\SAM>
ROOT KEY at offset: 0x001020 * Subkey indexing type is: 686c 
File size 65536 [10000] bytes, containing 5 pages (+ 1 headerpage)
Used for data: 298/27544 blocks/bytes, unused: 42/9160 blocks/bytes.


* SAM policy limits:
Failed logins before lockout is: 0
Minimum password length        : 0
Password history count         : 0
| RID -|---------- Username ------------| Admin? |- Lock? --|
| 01f4 | Administrador                  | ADMIN  |          |
| 01f7 | DefaultAccount                 |        | dis/lock |
| 01f5 | Invitado                       |        | dis/lock |
| 03ea | Usuario                        |        | *BLANK*  |
...
...
Si nos hemos fijado en un momento dado nos ha ofrecido la siguiente gama de acciones para realizar sobre el usuario:
 1 - Clear (blank) user password
 2 - Edit (set new) user password (careful with this on XP or Vista)
 3 - Promote user (make user an administrator)
 4 - Unlock and enable user account [probably locked now]
 q - Quit editing user, back to user select
Lo cual nos da una idea de la potencia del comando. Incluye incluso una opción de edición de registro que parece bastante peligrosa y de la que ya habĺe en su día para otra cosa.

Bueno, pues con el entuerto arreglado...¡feliz fin del verano!.