G A C E T A   D E   L I N U X
...haciendo a Linux un poco más divertido!
La línea de comando de Perl del mes:
El caso de los identificadores de usuario duplicados

Por Ben Okopnik
Traducción al español por Juan Manuel Vives Luzón
el día 22 de Diciembre 2002, para La Gaceta de Linux

Capítulo 1

El e-mail era corto, sucinto, e iba directo al asunto.

Woomert -
Seré breve, sucinto e iré directamente al asunto.
Fusión de tres compañías.
Administrador del sistema nervioso.
3000+ usuarios.
/etc/passwd.
UIDs.
Saludos,
Frink Ooblick

Woomert Foonly, el sabueso detective de las computadoras, se sonrió. El cliente se había explicado a gritos e incoherentemente por telefóno, con expresiones tales como "no funciona" y "necesito ayuda", siendo éstas las principales frases de su conversación. Woomert había envíado a Frink al lugar a fin de que investigase y lo expuesto más arriba era el resultado más satisfactorio alcanzado. Sólo faltaba dar con la solución;como apenas faltaban unas horas para que el cliente fuera desconectado, por aquella jornada, Woomert decidió usar su tiempo productivamente. A ver, ¿Dónde está mi almohada favorita?...

Capítulo 2

Fresco y dispuesto, Woomert llegó al lugar de los hechos e, inmediatamente, se topó con un excitado Frink.

 - "Woomert, es terrible. El archivo es demasiado largo como para buscar en él de forma manual y los identificadores de usuario están fuera del mapa. El administrador del sistema está contrito, a veces frenético y a veces muy asustado, casi ha perdido todo el cabello. ¿Qué podemos hacer?"

 - "No te preocupes, camarada... oh, lo siento. Estuve en Camberra apenas hace unas horas y todavía estoy influenciado. Puedo hablarte de horribles experiencias que mañana pueden ser todavía peores. Tengo que estar en Dallas por la mañana, en Nueva York al mediodía y en Tel Aviv por la tarde. Te recomiendo que uses tapones para los oídos o que te alejes de mi proximidad hasta que suavice mi acento. Ah, los peligros de viajar..."

Frink comenzaba a mostrarse perplejo.

 - "Woomert -no estás tomando esto en serio. ¿No te das cuenta de que esto es un problema grave?"

 - "Oh, ¿esto? Relájate, tómalo con calma. No es tan complejo como parece, Frink, en efecto.."

Woomert extrajo hábilmente de su bolsillo sus guantes favoritos para teclear y los deslizó en sus manos.

 - "...Perl hace de este problema un asunto trivial. Lo que vamos a hacer es darle al administrador del sistema un par de herramientos de línea de comandos que podrá usar para resolver este asunto y, desde que está usando "bash", será capaz de editarlas con la tecla de "cursor arriba" cada vez que las necesite, ¡Allá vamos!"


perl -F: -walne'$h{$F[2]}.="$F[0] ";END{$h{$_}=~/ ./&&print"$_: $h{$_}"for keys%h}' /etc/passwd
Una lista de identificadores de usuario duplicados, con sus nombres de usuario relativos, se deslizó pantalla abajo después de que Woomert pulsó la tecla "Enter". Woomert y Frink apreciaron que existía una entrada triplicada para UID0.

0: root sashroot kill3r

 - "Bien, Bien. Parece que alguién boicoteó la máquina y se dotó de una cuenta UID0 (root). El 'sashroot' es correcto - este es el 'standalone shell' para los trabajos de reparación menos finos -pero ¿'kill3r'? Bien, bien dejemos hacer al cliente; mientras tanto, sigamos con el problema actual. El administrador del sistema podrá contar ahora con una lista de todas las entradas duplicadas -no parece que haya demasiadas- pero buscar el siguiente identificador de usuario utilizable puede ser doloroso. Por tanto utilizaremos una segunda herramienta."


perl -wle'{getpwuid++$n&&redo;print$n}'
 - "Esto debería servirle para empezar a obtener directamente lo buscado y, a nosotros, para regresar a casa".

Capítulo 3

Cuando regresaron a casa de Woomert y se sentaron frente a la chimenea -la noche era fría y el viento soplaba detrás de la ventana- Frink miraba expectante a Woomert. Notando la mirada de Frink, Woomert reía.

 - "Lo se, debería explicartelo, ¿no?. El ambiente de misterio es placentero, pero no es nada comparado con el placer de aprender. Empezaremos por el principio:


perl -F: -walne'$h{$F[2]}.="$F[0] ";END{$h{$_}=~/ ./&&print"$_: $h{$_}"for keys%h}' /etc/passwd
"Primero, echa un vistazo a la linea de comando y los parámetros que he utilizado"
-w Activa alertas
-a Autodiscriminación (ver "-F")
-l Activa el proceso de finalde linea
-n Bucle implícito de no impresión
-e Ejecuta los siguientes comandos
-F Usa ':' como separador para el discriminador '-a'
"Si recuerdas nuestra última aventura , todo lo anterior excepto '-a' and '-F' debería resultarte familiar. Autosplitting discrimina las líneas leídas con '-n' o '-p', usando un espacio en blanco comp separador por defecto y guardando el resultado en el array '@F'. '-F' redefine opcionalmente el separador por el que vamos a efectuar la discriminación."

"Volvamos al punto en que vimos '/etc/passwd', y vamos a echar un vistazo al formato de sus órdenes individuales:"

borg:x:1026:127: ¡Toda la base nos pertenece!:/home/borg:/bin/bash
"Hay siete campos standard, que se presentan como 'name - passwd - UID - GID - GECOS - dir - shell'. Lo único que nos ineresaba por el momento era el nombre y el identificador de usuario; lo que hice fue construir un hash -una estructura de datos muy importante en Perl, una de las tres básicas -que contuviera el UID (tercer campo) como 'clave', y el nombre (primer campo), seguido por un espacio en blanco, como el 'valor', para todas las entradas existentes en '/etc/passwd':
$h{$F[2]}.="$F[0] "
Desde que los nombres de usuario no pueden contener espacios, esto funciona como un adecuado separador. Una vez hecho esto, hice un bucle sobre el hash e imprimí cualquier valor que contuviera un espacio en blanco seguido por cualquier caracter:"
 
$h{$_}=~/ ./&&print"$_: $h{$_}"for keys%h}
"Veo que todavía pareces perplejo. Dejame reescribir lo que escribí más arriba en forma más legible:"

for ( keys %h ){                # Efectúa un bucle sobre el hash "%h" 
    if ( $h{$_} =~ / ./ ){      #¿Contiente 'valor' un espacio seguido de algo?
        print "$_: $h{$_}\n";   # En ese caso, imprime el UID, una coma, un espacio, y 'valor'
    }
}

"Si reflexionas acerca de ello, podrás ver que lo único que coincide con el registro superior es un valor con más de un nombre, esto es, un UID duplicado."

 - "De acuerdo - ahora  ya veo cómo has obtenido el resultado. ¿Qué ocurre con la segunda expresión, aquella que dice 'siguiente UID disponible' ?"

 - "Ah, te refieres a esta:"


perl -wle'{getpwuid++$n&&redo;print$n}'

"No es otra cosa que un pequeño bucle con el que compruebo  si el identificador de usuario definido por '$n' existe. Si hay exito en la búsqueda - quiere decir que hay un UID igual a '$n' en uso - 'redo' es invocado, '$n' es incrementado, y la prueba comienza de nuevo. Si falla, en cualquier caso'$n' es imprimido en STDOUT y el programa finaliza su ejecución. Práctico y no muy complidado. Sólo un poco de trabajo y todo está hecho. Una brecha de seguridad es algo más complicado, pero, al menos, ahora la conocemos..."


Copyright © 2002, Ben Okopnik. Copying license http://www.linuxgazette.com/copying.html
Publicado en el número 85 de Linux Gazette, Diciembre 2002