Intéressé par des cours d'informatique en ligne ?
Visitez mon nouveau site https://www.yesik.it !

Sur certaines distributions Unix-like, le fichier /etc/environment permet de définir des variables d'environnement à l'échelle du système.

Mais /etc/environment ne fait pas partie des fichiers standards à proprement parler: en effet, sur la plupart des systèmes, son chargement est lié à la présence du module PAM ( Pluggable Authentication Modules – Un mécanisme flexible pour gérer l'authentification des utilisateurs en environnement Unix-like. Plus... ) . Celui-ci permet une gestion modulable (plugable) de l'authentification des utilisateurs. C'est lorsqu'un logiciel utilise PAM (et plus précisément pam_env), que ce dernier procède au chargement de /etc/environment. Et à l'initialisation dans le contexte du logiciel appelant des variables d'environnement qui y sont définies.

Commande PAM-aware.png

PAM — Quand une commande PAM-aware est invoquée – que ce soit par un utilisateur ou le système – elle charge le module PAM ( Pluggable Authentication Modules – Un mécanisme flexible pour gérer l'authentification des utilisateurs en environnement Unix-like. Plus... ) . Celui-ci examine le dossier /etc/pam.d ou à défaut /etc/pam.conf à la recherche de la configuration associée à ce programme.
La configuration précise quels modules enfichables doivent être chargés. Ces modules offrent diverses fonctionnalités pour assurer l'authentification des utilisateurs, la gestion de leurs droits ou encore la configuration de leur environnement. Par exemple, pam_time(8) permet de restreindre les horaires d'accès au système. Ou encore pam_env(8) permet d'initaliser les variables d'environnement à partir d'un fichier comme /etc/environment.

A titre d'exemple, voici le contenu de ce fichier sur ma machine Debian/Lenny:

sh$ cat /etc/environment
LANG="en_US.UTF-8"
SCALA_HOME=/usr/local/share/scala

/etc/environment n'est pas un script shell!

Il ne peut contenir que des paires CLE=VALEUR – et en particulier il ne permet pas d'effectuer des subtitutions dans les valeurs. Les exemples ci-dessous sont donc invalides.

INVALIDE – /etc/environment n'autorise pas les substitutions:

GROOVY_HOME=/usr/local/share/groovy
PATH=$PATH:$GROOVY_HOME:bin

INVALIDE – /etc/environment n'autorise pas les commandes shell:

GROOVY_HOME=/usr/local/share/groovy
export GROOVY_HOME

INVALIDE – /etc/environment n'utilise pas de délimiteur autour des valeurs:

GROOVY_HOME="/usr/local/share/groovy"

Selon la version utilisée par votre système, il se peut que pam_env s'accomode de l'une ou l'autre des syntaxes invalides ci-dessus. C'est d'ailleurs le cas sous Debian/Lenny puisque vous avez peut-être constaté que la valeur de LANG est définie avec des guillemets. Néanmoins, c'est une bonne habitude de s'en tenir à la syntaxe de base. Ne serait-ce que pour ne pas se retrouver face à de subtiles différences d'un système à l'autre – voire entre les programmes qui lisent /etc/environment via pam_env et ceux qui le lisent directement.

Dernier mot: les lignes invalides sont juste ignorées par pam_env(8). Donc si une variable semble mystérieusement ne pas être initialisée correctement, vérifiez que vous n'avez pas fait une quelconque faute de frappe.

Comment ça marche?

Les interactions entre PAM, /etc/environment et les utilitaires Unix semblent parfois mystérieuses au premier abord. Pour clarifier un peu les choses, voici ce qui se passe (toujours sur ma machine Debian/Lenny) quand le système exécute la commande PAM-aware su(1).

Tout d'abord, su charge PAM qui va chercher dans /etc/pam.d si une configuration portant le même nom que le programme lancé est présente. Et effectivement, il trouve /etc/pam.d/su. Voici la section de ce fichier qui nous intéresse ici:

...
# This module parses environment configuration file(s)
# and also allows you to use an extended config
# file /etc/security/pam_env.conf.
# 
# parsing /etc/environment needs "readenv=1"
session       required   pam_env.so readenv=1
...

Tout le truc est dans la règle ci-dessus: celle-ci spécifie le chargement du module pam_env. Dont le rôle est d'initialiser des variables d'environnement. Et par défaut, les variables et leur valeurs sont extraites de /etc/environment. Autrement dit, tout programme utilisant PAM et pour lequel la règle ci-dessus est définie charge les variables d'environnement définies dans /etc/environment.

Ceci dit, pam_env peut aussi charger des variables définies dans d'autres fichiers. Comme illustré par la règle suivante:

...
# locale variables are also kept into /etc/default/locale in etch
# reading this file *in addition to /etc/environment* does not hurt
session       required   pam_env.so readenv=1 envfile=/etc/default/locale
...

Ici, pam_env va aussi charger les variables définies dans /etc/default/locale.

Comme vous le voyez, le fichier /etc/environment n'a rien de magique. Et son chargement est conditionné à l'utilisation de PAM, du module pam_env et de la règle adéquate dans /etc/pam.d. Beaucoup de choses... la bonne nouvelle étant que sur un système moderne, la quasi totalité des programmes qui permettent de se connecter au système sont PAM-aware: login, su, sudo, sshd, gdm, ...

Et init?

Init, su et environnement.png

Dans mon script de démarrage de JBoss pour Linux, je lance ce service via un appel à su. C'est la seule commande PAM-aware de la séquence de démarrage. Mais c'est suffisant pour que JBoss ait accès à l'environnement défini dans /etc/environment.

Mauvaise pioche! init(8) n'utilise pas PAM... Ceci dit, sous certains systèmes comme IBM AIX, init lit quand même le fichier /etc/environment. Ça n'est pas le cas sous Linux.

Au premier abord, cela peut sembler dommage, puisque les services à lancer au démarrage de la machine pourraient avoir besoin d'accéder à l'environnement défini dans /etc/environment.

Mais en réalité, ça n'est pas un si gros obstacle que ça. En effet, vous savez qu'il est vivement déconseillé de démarrer un service sous l'identité root. Donc, à un moment ou un autre, le script de démarrage pourra faire appel à une commande comme su ou sudo pour lancer le service sous une identité dotée de privilèges réduits. Or ces commandes utilisent PAM. Donc le serveur aura finalement accès à l'environnement défini dans /etc/environment. CQFD!

Ah, oui, au pire, si vous avez quand même besoin de l'environnement defini dans /etc/environment en dehors du contexte créé par un appel à su ou sudo (ou n'importe quelle autre commande PAM-aware), vous pouvez toujours sourcer ce fichier dans vos scripts shells:

# Source /etc/environment pour sh(1) (ou compatible)
[ -r /etc/environment ] && . /etc/environment

Comment savoir?

Pour ceux qui veulent savoir si un programme utilise PAM ou pas, il est possible d'utiliser ldd(1). Si libpam apparaît dans la liste des bibliothèques utilisées, c'est la cas. Sinon...

# su(1) utilise PAM:
sh$ ldd /bin/su
 	linux-gate.so.1 =>  (0xb7fc1000) 
	libpam.so.0 => /lib/libpam.so.0 (0xb7fa4000)
	libpam_misc.so.0 => /lib/libpam_misc.so.0 (0xb7fa1000)
	libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb7e45000)
	libdl.so.2 => /lib/i686/cmov/libdl.so.2 (0xb7e41000)
	/lib/ld-linux.so.2 (0x80000000)

# init(8) n'utilise pas PAM:
sh$ ldd /sbin/init
	linux-gate.so.1 =>  (0xb7ef5000)
	libsepol.so.1 => /lib/libsepol.so.1 (0xb7eae000)
	libselinux.so.1 => /lib/libselinux.so.1 (0xb7e95000)
	libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb7d39000)
	libdl.so.2 => /lib/i686/cmov/libdl.so.2 (0xb7d35000)
	/lib/ld-linux.so.2 (0xb7ef6000)

Ressources