LightDM sous Ubuntu 11.10 : Problème avec les homedirs NFS et l’option root_squash

LightDM 1.0.6 est le gestionnaire de connexions fourni par défaut sous (X)ubuntu 11.10.
Hors il s’avère qu’il est impossible de démarrer une session lorsque le répertoire personnel de l’utilisateur cherchant à se logguer se trouve sur un partage NFS possédant dans ses options d’export l’option root_squash et que les droits du répertoire personnels sont à 700.

L’option root_squash permet d’éviter que le root de la machine cliente ait les droits root sur le serveur NFS en mappant son UID(0) vers l’UID de l’utilisateur Nobody.

En regardant le code source de lightdm 1.0.6, dans le fichier session.c, nous y voyons :

    /* Change working directory */
    if (chdir (user_get_home_directory (user)) != 0)
    {
        g_warning ("Failed to change to home directory %s: %s", user_get_home_directory (user), strerror (errno));
        _exit (EXIT_FAILURE);
    }

    /* Change to this user */
    if (getuid () == 0)
    {
        if (initgroups (user_get_name (user), user_get_gid (user)) < 0)
        {
            g_warning ("Failed to initialize supplementary groups for %s: %s", user_get_name (user), strerror (errno));
            _exit (EXIT_FAILURE);
        }

        if (setgid (user_get_gid (user)) != 0)
        {
            g_warning ("Failed to set group ID to %d: %s", user_get_gid (user), strerror (errno));
            _exit (EXIT_FAILURE);
        }

        if (setuid (user_get_uid (user)) != 0)
        {
            g_warning ("Failed to set user ID to %d: %s", user_get_uid (user), strerror (errno));
            _exit (EXIT_FAILURE);
        }
    }

Nous voyons donc que changement de répertoire a lieu avant le changement d’UID/GID. Sur un système classique cela ne pose pas de soucis car le root a toujours le droit de traverser un répertoire.
Cependant, du fait de l’option root_squash au niveau du partage NFS, ceci n’est plus vrai et donc le programme s’arrête suite à la vérification de la condition (chdir (user_get_home_directory (user)) != 0).

Pour venir à bout de ce problème, nous avons trois possibilités :

– Enlever l’option root_squash mais ceci ajoute une brèche dans la sécurité du service NFS
– Passer les droits sur les répertoires personnels des utilisateurs en 701. De cette manière, l’utilisateur root mappé pourra traverser le répertoire et donc cela ne générera plus d’erreur. Cela peut néanmoins être contraignant s’il y a beaucoup de homedirs à traiter.
– Modifier le code source de LightDM pour inverser la procédure :

    /* Change to this user */
    if (getuid () == 0)
    {
        if (initgroups (user_get_name (user), user_get_gid (user)) < 0)
        {
            g_warning ("Failed to initialize supplementary groups for %s: %s", user_get_name (user), strerror (errno));
            _exit (EXIT_FAILURE);
        }

        if (setgid (user_get_gid (user)) != 0)
        {
            g_warning ("Failed to set group ID to %d: %s", user_get_gid (user), strerror (errno));
            _exit (EXIT_FAILURE);
        }

        if (setuid (user_get_uid (user)) != 0)
        {
            g_warning ("Failed to set user ID to %d: %s", user_get_uid (user), strerror (errno));
            _exit (EXIT_FAILURE);
        }
    }
    /* Change working directory */
    if (chdir (user_get_home_directory (user)) != 0)
    {
        g_warning ("Failed to change to home directory %s: %s", user_get_home_directory (user), strerror (errno));
        _exit (EXIT_FAILURE);
    }

Ainsi, on change l’UID/GID avant de traverser le répertoire. En tout état de cause, un utilisateur doit avoir accès à son répertoire personnel et si ce n’est pas le cas, alors une erreur sera signalée.

Pour plus de facilité, j’ai reconstruis des paquets (X)ubuntu corrigeant cette erreur :

L’installation, après téléchargement des paquets se fait a l’aide de la commande :

sudo dpkg --install xxxxxxxx.deb

Donner un look Unity au LightDM de Xubuntu

Par défaut, sur Xubuntu 11.10, LightDM ressemble à :

Dans cet article, nous allons essayer de le faire ressembler au LightDM d’Ubuntu 11.10 tout en gardant la charte graphique de Xubuntu.

Tout d’abord, installons les paquets nécessaires :

sudo apt-get install gnome-settings-daemon indicator-session-gtk2 unity-greeter ubuntu-mono light-themes

Modifions le fichier /etc/lightdm/lightdm.conf :

[SeatDefaults]
user-session=xubuntu
greeter-session=unity-greeter

Bien évidemment, vous pouvez garder vos autres personnalisations dans ce fichier. Seule la ligne greeter-session est importante.

Éditons ensuite le fichier /etc/lightdm/unity-greeter.conf pour remplacer la ligne :

background=/usr/share/backgrounds/warty-final-ubuntu.png

par

background=/usr/share/xfce4/backdrops/xubuntu-greybird.png

et

logo=/usr/share/unity-greeter/logo.png

par

logo=/usr/share/pixmaps/xubuntu.png

Ensuite, téléchargeons le logo déclaré précédemment :

sudo wget -O /usr/share/pixmaps/xubuntu.png http://www.be-root.com/downloads/xubuntu/xubuntu.png

Redémarrons LightDM :

service lightdm restart

Nous obtenons alors un écran d’accueil semblable à celui d’Ubuntu 11.10 :

Puppet : utilisation des templates

Dans les précédents articles ( installation de puppet et configuration simple ), nous avons vu comment installer et utiliser puppet à l’aide de fichiers de configurations statiques, ne variant pas d’un hôte à l’autre.

Dans cet article nous allons voir comment utiliser les templates. Un template est un fichier de configuration qui sera envoyé à un client mais dont le contenu sera adapté à ce dernier. Puppet fait usage du moteur de template ERB développé pour ruby. Les variable utilisés par les templates peut être soit des « facts », soit des variables positionnées manuellement.

Utilisation des facts

Les facts sont des scripts ruby (placés sous /usr/lib/ruby/facter/) et exécutés sur la partie cliente de puppet. Ces scripts positionnent des variables en fonction le l’environnement d’exécution. La commande système facter | less permet de lister les variables affectées.

Dans le précedent article, nous avons utilisé dans le module ssh des lignes du type name => $operatingsystem afin de déterminer le système d’exploitation du client. La variable $operatingsystem est positionnée par le fact operatingsystem.rb.

Dans l’exemple que nous allons détailler, nous allons utiliser des variables assignées par les facts pour générer un fichier /etc/motd sur les postes clients.

Tout d’abord, créons les répertoires du module que nous allons appeler motd :

mkdir -p /etc/puppet/modules/motd/{files,templates,manifests}

Ensuite, créons le fichier /etc/puppet/modules/motd/manifests/init.pp :

class motd::config {
        file {"/etc/motd":
                        owner  => 'root',
                        group  => 'root',
                        mode   =>  0644,
                        content=> template("/etc/puppet/modules/motd/templates/motd.erb"),
        }
}

class motd {
        include motd::config
}

La classe motd est plutôt simple puisqu’elle ne s’occupe du fichier /etc/motd.
Contrairement à un fichier statique dont la source serait définie par une syntaxe du type source => « puppet:///modules/files/motd », ici la syntaxe pour l’utilisation d’un template comporte le chemin absolu vers celui-ci (content=> template(« /etc/puppet/modules/motd/templates/motd.erb »)).

Créons notre fichier /etc/puppet/modules/motd/templates/motd.erb :

Welcome to <%= @hostname %> running <%= @operatingsystem %> <%= @operatingsystemrelease %> ( <%= @kernelrelease %> )
 * Documentation:  https://help.ubuntu.com

Les variables à inclure sont définies entre les balises <%= et %>.
hostname, operatingsystem, operatingsystemrelease et kernelrelease sont des variables affectées par les facts.

Afin d’utiliser la classe motd, il suffit de l’affecter à notre machine poste-client en modifiant le fichier /etc/puppet/manifests/nodes.pp :

node 'poste-client.be-root.com' {
        include         ssh, motd
}

Lorsque le puppet-agent du poste client aura mis en place la nouvelle configuration, nous obtenons le fichier /etc/motd :

Welcome to poste-client running Ubuntu 11.10 ( 3.0.0-15-generic )
 * Documentation:  https://help.ubuntu.com

Il est possible de créer ses propres facts. Ceci est expliqué dans la documentation de puppet

Un peu plus loin avec les templates

Il est possible de définir hôte par hôte des variables à utiliser dans les templates.
Nous allons voir dans cet exemple comment adapter la configuration du serveur proftpd.

Tout d’abord, créons l’arborescence du module proftpd :

mkdir -p /etc/puppet/modules/proftpd/{files,templates,manifests}

Créons le fichier /etc/puppet/modules/proftpd/manifests/init.pp :

class proftpd::install {
        package { "proftpd-basic":
                 ensure => latest,
        }
}

class proftpd::config {
        file {"/etc/proftpd/proftpd.conf":
                        owner  => 'root',
                        group  => 'root',
                        mode   => 0644,
                        content=> template("/etc/puppet/modules/proftpd/templates/proftpd.conf.erb"),
                        require=> Class["proftpd::install"],
                        notify => Class["proftpd::service"],
        }
}

class proftpd::service {
        service { "proftpd":
                        ensure     => running,
                        hasstatus  => true,
                        hasrestart => true,
                        enable     => true,
                        require    => Class["proftpd::config"],
        }
}

class proftpd {
        include proftpd::install, proftpd::config, proftpd::service
}

Si vous avez bien assimilé l’exemple de la classe ssh ainsi que la classe motd, la compréhension de ce fichier ne doit poser aucun problème.

Créons maintenant le fichier /etc/puppet/modules/proftpd/templates/proftpd.conf.erb :

# PROFTPD
# DON'T MODIFY THIS FILE DIRECTLY - MANAGED BY PUPPET
UseIPv6                         off
IdentLookups                    off
ServerName                      <%= @hostname %>
ServerType                      standalone
DeferWelcome                    off
MultilineRFC2228                on
DefaultServer                   on
ShowSymlinks                    on
TimeoutNoTransfer               600
TimeoutStalled                  600
TimeoutIdle                     1200
ListOptions                     "-l"
DenyFilter                      \*.*/

<% if @proftpd_chroot == true %>
 DefaultRoot ~
<% end %>

Port                            <%= @proftpd_port %>

MaxInstances                    <%= @proftpd_maxinstances %>

# Set the user and group that the server normally runs at.
User                            proftpd
Group                           nogroup

Umask                           022  022
AllowOverwrite                  on

TransferLog /var/log/proftpd/xferlog
SystemLog   /var/log/proftpd/proftpd.log

Nous remarquons que seule la variable hostname est fournie par un fact. Il nous faudra donc positionner les autres.
Nous remarquons que nous pouvons également mettre des instructions ruby dans les balises <% et %> (ici une condition if). Pour plus d’informations, consultez cette page.

Nous allons donc positionner les variables et assigner la classe proftpd à poste-client dans le fichier /etc/puppet/manifests/nodes.pp :

node 'poste-client' {
        $proftpd_chroot         =  false
        $proftpd_port           =  21
        $proftpd_maxinstances   =  25
        include         ssh, motd, proftpd
}

Ceci permet, à l’aide d’une seule classe, de pouvoir gérer plusieurs configurations différentes. Par exemple, on peut imaginer avoir :

node 'poste-client' {
        $proftpd_chroot         =  false
        $proftpd_port           =  21
        $proftpd_maxinstances   =  25
        include         ssh, motd, proftpd
}

node 'serveur-ftp' {
        $proftpd_chroot         =  true
        $proftpd_port           =  21
        $proftpd_maxinstances   =  300
        include         ssh, proftpd
}

Nous voyons donc qu’il est possible, à l’aide des templates, de pouvoir gérer efficacement et simplement des configurations différentes pour un même service.