domingo, 15 de febrero de 2009

Con tu permiso, HAL

Expresemos parte de lo visto en los dos artículos precedentes en forma de un diálogo real, al modo como lo hicimos hace algún tiempo, pero esta vez incluidas también "las reflexiones" del propio HAL. Aparte de ser un experimento divertido, allanará definitivamente el camino hacia la siguiente y muy importante estación. [Omitimos otras muchas reflexiones que hace HAL y que todavía no han sido explicadas y nos limitamos sólo a aquellas que atañen al tema actual.]

YO:
Acabo de crear el fichero 'prueba' en mi directorio 'guiones', en el que precisamente estoy en este momento, y quiero que HAL lo ejecute como si se tratase de una orden más.

prueba


HAL:
Veo en la línea de órdenes el nombre 'prueba'. Puesto que es la primera ---y aquí única--- palabra en la línea de órdenes, se trata del nombre de un fichero ejecutable. Como este nombre no es la ruta completa de un fichero ejecutable, debo construir yo mismo la ruta completa a partir de la información contenida en la variable 'PATH' que es donde están definidas las rutas completas de los directorios que contienen ficheros ejecutables. Añadiré, pues, el nombre de fichero 'prueba' a la ruta de cada directorio definido en 'PATH'.

El primer directorio en 'PATH' es '/usr/local/bin'. Por tanto, la ruta completa del fichero que me han dado es '/usr/local/bin/prueba'. No encuentro este fichero. Repetiré el proceso para el siguiente directorio en 'PATH'.


[HAL repite el mismo paso para los demás directorios: '/usr/bin', '/bin', '/usr/bin/X11' y '/usr/games' y obtiene el mismo resultado: fichero no encontrado]

El fichero no se ha encontrado. Tengo una respuesta preparada para esta situación, que imprimo en la salida

bash: prueba: command not found


YO:
La orden no se ha encontrado porque mi directorio '/home/atopos/guiones' no está incluido en la variable 'PATH'. En lugar de cambiar la variable voy a dar a HAL la ruta completa de mi fichero 'prueba' por medio de una abreviatura:

./prueba


HAL:
Veo en la línea de órdenes la expresión './prueba'. El primer signo es una abreviatura del directorio actual de trabajo. Lo primero que debo hacer es expandir la abreviatura. Esto me da como resultado:

/home/atopos/guiones/prueba

Puesto que ésta es la primera ---y aquí única--- expresión en la línea de órdenes, se trata del nombre de un fichero ejecutable.

Antes de ejecutarla, compruebo los permisos de ejecución del fichero. El usuario atopos no tiene permisos para ejecutar el fichero. Tengo una respuesta preparada para esa situación, que imprimo en la salida:


bash: /home/atopos/guiones/prueba: Permiso denegado


YO:
Increíble, pero cierto. Incluso estando en nuestro 'home' particular, HAL nos dice que no tenemos permisos. ¡Esto sí que es un galimatías!


La reflexión de HAL que precede a su desconcertante respuesta sobre los permisos alude un aspecto crucial en el que hay que detenerse.

Ya vimos al comienzo de estas conversaciones que HAL es un sistema multiusuario. También sabemos que al menos dos usuarios han de convivir en HAL, nosotros y el superusuario, y que no todos los usuarios tiene los mismos privilegios en el sistema, como se deduce del hecho de que el superusuario tenga todos y nosotros sólo algunos.

Pero la cosa es algo más compleja y sofisticada que la mera distinción entre un usuario superpoderoso y el resto de los mortales. Y lo es en aras de nuestra seguridad y de la del sistema en conjunto. Veamos en qué consiste básicamente esta complejidad. Lo mínimo necesario como para poder entender la anterior y desconcertante respuesta de HAL.

En primer lugar, todo fichero que reside en HAL ---también todo directorio y toda instancia de un programa en ejecución, pero nosotros nos limitaremos sólo a hablar de ficheros, que es lo que necesitamos ahora--- se considera propiedad de un usuario del sistema y de un grupo de usuarios del sistema, y, téngase en cuenta, que todo usuario, a su vez, es siempre miembro de uno o varios grupos. Los usuarios que ---mala suerte--- no son propietarios de un fichero ni pertenecen a un grupo que tenga derechos de propiedad sobre ese fichero son, en relación con ese fichero, unos don nadie y se los denomina los otros en general.

Sobre esta división horizontal del inmueble en que consiste el sistema de ficheros de HAL, se cruza otra caracterización, relativa a las acciones que se pueden realizar con dichos ficheros, y que son, básicamente, tres: leer, escribir y ejecutar un fichero.

Estas dos categorizaciones se entreveran, como decimos, y forman una trama bidimensional en torno a todos los ficheros del sistema. Dicho de otra forma, sobre cada fichero se puede construir una tabla donde se relacionan propietarios y acciones. Por ejemplo, para nuestro fichero prueba podríamos construir una tabla del siguiente tipo:

Fichero prueba [propietarios-acciones]
/-----------------------------------------------------\
| | leer | escribir | ejecutar |
|-----------------------------------------------------|
| usuario | | | |
|-----------------------------------------------------|
| grupo | | | |
|-----------------------------------------------------|
| otros | | | |
\-----------------------------------------------------/

Mediante esta tabla podemos establecer un mecanismo de control fino sobre lo que cada propietario ---o don nadie--- puede hacer con un fichero en el sistema, establecer los permisos que dichos usuarios tienen o no tienen en relación con ese fichero. El conjunto de permisos de un fichero de HAL, organizados de la forma indicada, se denomina el modo de ese fichero.

Consideremos, por ejemplo, nuestro fichero prueba. Su usuario propietario es, en mi caso, atopos ---en el del lector, será su nombre de usuario. El usuario atopos pertenece, a su vez, a un grupo con el mismo nombre, atopos, el cual también tiene derechos de propiedad sobre ese fichero. Pues bien, el modo de este fichero, esto es, la secuencia de permisos correspondientes a todos sus posibles usuarios, es actualmente el siguiente:

Fichero prueba [permisos = modo]
/------------------------------------------------------\
| | leer | escribir | ejecutar |
|------------------------------------------------------|
| U:atopos | Permitido | Permitido | No permitido |
|------------------------------------------------------|
| G:atopos | Permitido | No permitido | No permitido |
|------------------------------------------------------|
| otros | Permitido | No permitido | No permitido |
\------------------------------------------------------/

Esta tabla se puede escribir también de esta otra forma (donde 1 está por "Permitido" y 0 por "No permitido"):

/--------------------------------------------------------------------------------------\
| usuario:atopos | grupo:atopos | otros |
|--------------------------------------------------------------------------------------|
| leer | escribir | ejecutar | leer | escribir | ejecutar | leer | escribir | ejecutar |
|--------------------------------------------------------------------------------------|
| 1 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 |
\--------------------------------------------------------------------------------------/

O, también de esta otra, si en lugar de los términos "leer", "escribir" y "ejecutar", ponemos una letra de sus equivalencias en inglés (read, write y execute):

/-----------------------------------\
| U:atopos | G:atopos | otros |
|-----------------------------------|
| r | w | x | r | w | x | r | w | x |
|-----------------------------------|
| 1 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 |
\-----------------------------------/

Todavía podemos abreviar la tabla canónica anterior de dos formas distintas.

La primera consiste en suprimir la última fila y mantener la letra de la penúltima allí donde su valor sea 1 (= "Permitido") o sustituirla por un guión donde su valor sea 0 (= "No permitido"):

/-----------------------------------\
| U:atopos | G:atopos | otros |
|-----------------------------------|
| r | w | - | r | - | - | r | - | - |
\-----------------------------------/

La segunda forma de abreviar la tabla canónica en cuestión es suprimir directamente la fila intermedia, o sea:

/-----------------------------------\
| U:atopos | G:atopos | otros |
|-----------------------------------|
| 1 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 |
\-----------------------------------/

Todo esto está muy bien ---dirá el lector---, pero no se ha explicado todavía cómo ha llegado el autor a adivinar el modo del fichero prueba, es decir, la secuencia de permisos que lo caracteriza.

No se trata de una adivinanza. El modo de cualquier fichero se puede conocer perfectamente con una orden familiar, la orden ls, la que sirve para listar el contenido de un directorio. Existe una opción de ls que nos da una información detallada de ese contenido. Se trata de la opción -l ('L' minúscula, abreviatura del inglés long). Es bueno saber también que, aunque ls, sin argumentos, lista el contenido completo del directorio en que se ejecuta, puede recibir un fichero concreto como argumento. Veamos qué nos dice HAL si le pedimos que nos dé una información detallada sobre el fichero prueba, que, como sabemos, está en nuestro directorio guiones, al cual debe cambiar el lector, si no lo ha hecho todavía, con cd guiones:

ls -l prueba

La respuesta es la siguiente:

-rw-r--r-- 1 atopos atopos 4 feb 13 01:38 prueba

No es momento de entender cada elemento de esta respuesta. Basta con atender ahora a las siguientes columnas subrayadas:

-rw-r--r-- 1 atopos atopos 4 feb 13 01:38 prueba
========= ====== ======
MODO U G

El modo rw-r--r-- es exactamente el que apareció antes en forma tabular, salvo que se sobrentiende el orden de los tipos de usuario: los tres primeros corresponden al usuario propietario del fichero, los tres siguientes al grupo propietario del fichero y los tres últimos a los otros, que no son propietarios. (El guión que precede al modo no debe confundir al lector, se trata simplemente de una indicación de que el fichero es justo eso, un fichero normal y corriente y no, por ejemplo, un directorio, en cuyo caso ese guión sería sustituido por la letra 'd'). Las otras dos columnas obviamente indican el nombre del usuario y grupo, respectivamente, que son propietarios del fichero.

Podemos hacer una prueba más con la orden ls -l, por ejemplo, darle como argumento el fichero /etc/locale.gen al que nos referimos en una de nuestras primeras conversaciones:

ls -l /etc/locale.gen

Que devuelve un modo de fichero idéntico, aunque el usuario y el grupo son ahora distintos:

-rw-r--r-- 1 root root 8231 ene 21 13:29 /etc/locale.gen
========= ==== ====


Regresemos al caso de nuestro fichero prueba. Hemos visto que nosotros somos sus usuarios propietarios y que, de entre todos los usuarios del sistema, somos los que gozamos de más privilegios sobre él (derechos de lectura y escritura, frente a los de solo lectura, que tienen otros usuarios del grupo de mi mismo nombre y el resto de usuarios, que, en consecuencia, no podrán modificar el fichero de forma alguna). Esto es algo perfectamente natural, puesto que somos nosotros mismos los creadores del fichero, y sólo a nosotros nos debe estar permitido modificar lo que es patrimonio de nuestra inventiva.

Que el citado fichero y, en general, todos los demás ficheros que creemos en nuestro home adquieran de antemano esta definición de privilegios, este modo, es algo que hace HAL por nosotros. Podríamos, si lo quisiésemos, modificar este comportamiento de HAL, por ejemplo, hacer que todos los ficheros que creásemos activasen el permiso de ejecución para nosotros mismos. Pero no sería, en absoluto, conveniente. ¿Por qué? En primer lugar, porque un fichero ejecutable es, en principio, un caso excepcional en nuestro home. La gran mayoría de nuestros ficheros no van a ser órdenes que deba ejecutar HAL. Una imagen, un fichero de audio, un fichero que albergue nuestra última novela no son ficheros que contienen instrucciones ejecutables. En segundo lugar, y ésta es una razón aún más importante, no es razonable activar la posibilidad de ejecución para todo fichero. Quién sabe lo que un usuario malintencionado podría hacer si descubre que todo fichero de nuestro home es potencialmente ejecutable.

Puesto que el modo que, por defecto, asigna HAL a todos nuestros ficheros es el descrito, esto es, rw-r--r--, cuando creemos un fichero ejecutable tendremos, además, que modificar estos permisos, cambiar su modo (change mode), para que adopte al menos esta forma: rwxr--r--, es decir, para que al menos nosotros mismos, sus propietarios, podamos ejecutarlo.

Pidámosle, pues, a HAL que cambie el modo de nuestro fichero prueba:

chmod u+x prueba

Podemos comprobar el resultado:

ls -l prueba

Veremos esto:

-rwxr--r-- 1 atopos atopos 4 feb 13 01:38 prueba
=========

La orden chmod, que es, como vemos, la que permite cambiar el modo de un fichero, toma como primer argumento el nuevo modo del fichero. En el caso del ejemplo este nuevo modo viene expresado por una representación simbólica del cambio que se quiere realizar. El formato general de esta representación simbólica consta de tres partes:

tipo(s)-de-usuario(s)[+/-]acción

Aquí, los tipo(s)-de-usuario(s) son u, para usuario propietario; g, para el grupo propietario; o para otros. Los signos '+' y '- dan o quitan, respectivamente, el permiso al tipo de usuario especificado en la primera parte de la expresión. Finalmente, la última parte de la expresión establece la acción ---lectura (r), escritura (w) o ejecución (x)--- para la que se concede o deniega el permiso.

Así, en nuestro caso, u+x significa que queremos que el nuevo modo conceda (+) el permiso de ejecutar el fichero (x) al usuario propietario del mismo (u). Si quisiésemos conceder el permiso de ejecución a todos los tipos de usuarios, pondríamos ugo+x, que abreviadamente se puede escribir también a+x, donde a es una abreviatura de all (todos, en inglés). Si, por el contrario, quisiésemos denegar el permiso de lectura a todos los usuarios o grupos menos el propietario del fichero, la expresión sería go-r.

Existe otra forma de indicar el modo, que para algunos usuarios con predisposición matemática resulta más cómoda o intuitiva. Se trata de indicarla numéricamente, utilizando la cadena de dígitos que vimos antes. Según esta cadena, el modo de nuestro fichero prueba antes del cambio es: 110100100. Si queremos activar el permiso de ejecución para el usuario propietario, el nuevo modo sería 111100100. Ahora bien, en lugar de utilizar esta representación binaria (en base 2) se usa y debe usarse su equivalencia en octal (en base 8). 110100100 equivale en octal a 644, mientras que el nuevo modo, 111100100, equivale en octal a 744. Por tanto la anterior orden de cambio de modo se podría haber escrito de esta forma:

chmod 744 prueba

Animo al lector a que practique por su cuenta diversos cambios de modo con chmod, ya sea mediante la representación simbólica o la numérica. En este último caso, le puede venir bien echar mano de la clásica calculadora de HAL, bc, que se puede usar en modo interactivo o, mejor incluso, en una tubería. Por ejemplo, para obtener la representación en octal del número binario 111100100, podríamos utilizar la orden:

echo "obase=8; ibase=2; 111100100" | bc

donde obase indica la base numérica del dato de salida (output base) e ibase la del dato de entrada (input base).

Tras esta prolongada zambullida en el mundo de los permisos de ficheros de HAL y, una vez cambiado el modo del fichero prueba, que, como se recordará, contiene, sólo la línea pwd, podemos por fin hacer que HAL lo ejecute como una orden, sin temor a que nos vuelva a negar el permiso:

./prueba

Ahora sí podemos respirar tranquilos, porque el resultado es exactamente el que debe ser:

/home/atopos/guiones


Resumen:

  • HAL dispone de un riguroso sistema de control de acceso a sus ficheros según el tipo de usuario que se sea. Hay tres tipos de usuario: usuario propietario del fichero, grupo de usuarios propietarios del fichero y el resto de usuarios, los otros, que no son propietarios del fichero. Cada uno de estos usuarios puede recibir o no el permiso de lectura, de escritura o de ejecución sobre un determinado fichero.

  • Por defecto, HAL asigna un modo de control de acceso, una secuencia de privilegios, a cada fichero.

  • La opción -l de la orden ls nos da una información detallada de los ficheros que se le den como argumentos o, si no se le dan argumentos, de todos los ficheros del directorio desde la que se ejecuta. Esta información detallada incluye el modo del fichero y el nombre de sus propietarios.

  • La orden chmod permite cambiar el modo de un fichero. Por ejemplo, chmod u+x mi-orden añade el permiso de ejecución para el usuario propietario del fichero mi-orden.

  • bc es la clásica calculadora de HAL para la consola.

No hay comentarios:

Publicar un comentario