pacman, générer la clé depuis une session ssh

pacman est passé en version 4.0.1 sur le dépôt [core], du coup, j’ai mis certaines de mes installations accessibles qu’en ssh; or là, la génération de la clé reste bloquée :

# pacman-key --init
gpg: /etc/pacman.d/gnupg/trustdb.gpg: trustdb created
gpg: no ultimately trusted keys found
gpg: Generating pacman keychain master key...

Not enough random bytes available.  Please do some other work to give
the OS a chance to collect more entropy! (Need 281 more bytes)

Sur un « desktop », il suffira de bouger une fenêtre pendant plus ou moins longtemps afin que ça fonctionne; depuis une session ssh, c’est moins évident …
On peut néanmoins y remédier en installant rng-tools puis, modifier le fichier /etc/conf.d/rngd :

timeout=10

Lancez dans une session ssh en root :

rngd -f -r /dev/urandom

Et dans une autre session ssh :

pacman-key --init

Ca devrait fonctionner sans souci.

Archlinux, un serpent est mort

Avec pacman 4.x, on verra la mort d’un des serpents de mer d’Arch Linux : la signature des paquets et dépôts.

Souvent et de manière récurrente, il fleurissait ici ou là un sujet concernant la sécurité des paquets sous Arch Linux (Dan McGee résume cela dans un article), mais jusqu’à maintenant, aucune implémentation n’avait percée, désormais, c’est chose faite.

Il est maintenant possible de signer les dépôts (à l’aide de repo-add -s) mais aussi les paquets (à l’aide de makepkg --sign), pacman, lors de la phase de vérification d’intégrité et selon la configuration, teste les signatures.

Plusieurs niveaux de vérification sont possibles selon la valeur de la directive SigLevel:

SigLevel = [Database|Package]<Required|Optional|Never> [TrustOnly|TrustAll]

Il est possible de spécifier une configuration globale en plaçant SigLevel dans la section [options] et/ou une configuration par dépôt en la plaçant dans la section du dépôt concerné, par exemple:

[options]
#...
SigLevel = Optional TrustOnly
#...
[mon_depot]
SigLevel = DatabaseRequired PackageNever TrustOnly

Le fonctionnement ensuite, est totalement transparent à moins qu’une vérification échoue.

Un exemple vaut mieux qu’un long discours et pour avoir un aperçu de tout le cheminement, je vais créer un mini dépôt contenant yaourt-git et package-query-git, les versions stables n’étant pas compatibles avec pacman, ça tombe bien.

Evidemment, il faut avoir une clé pour procéder aux signatures :

$ gpg --fingerprint
/home/test/.gnupg/pubring.gpg
-----------------------------
pub   2048R/EB671452 2011-10-25
    Empreinte de la clé = 8002 883C D06C 06BB BDD1  4D24 C2B0 9F4B EB67 1452
uid                  tuxce <tuxce archlinux.fr>
uid                  tuxce <tuxce.net gmail.com>
uid                  [jpeg image of size 11842]
sub   2048R/DE00D30D 2011-10-25

On récupère les PKGBUILD :

mkdir pkg repo
cd pkg
for pkg in yaourt-git package-query-git; do
  curl http://aur.archlinux.org/packages/$pkg/$pkg.tar.gz | bsdtar -xf -
done

On construit les paquets:

$ cd ..
$ export PKGDEST="$(pwd)/repo"
$ cd pkg/yaourt-git
$ makepkg --sign
# [...]
==> Signature de(s) paquet(s)…

Vous avez besoin d'une phrase de passe pour déverrouiller la
clé secrète pour l'utilisateur: « tuxce  »
clé de 2048 bits RSA, ID EB671452, créée le 2011-10-25

  -> Le fichier /home/test/pkg/yaourt-git/yaourt-git-20111025-1-any.pkg.tar.xz.sig des signatures a été créé.
==> Quitte l'environnement fakeroot.
==> Création finie : yaourt-git 20111025-1 (mar. oct. 25 17:04:14 CEST 2011)
$ cd ../package-query-git
# [...]
==> Signature de(s) paquet(s)…
                           
Vous avez besoin d'une phrase de passe pour déverrouiller la
clé secrète pour l'utilisateur: « tuxce  »
clé de 2048 bits RSA, ID EB671452, créée le 2011-10-25

  -> Le fichier /home/test/pkg/package-query-git/package-query-git-20111025-1-x86_64.pkg.tar.xz.sig des signatures a été créé.
==> Quitte l'environnement fakeroot.
==> Création finie : package-query-git 20111025-1 (mar. oct. 25 17:06:47 CEST 2011)

Création du dépôt:

$ cd ../../repo
$ ls
package-query-git-20111025-1-x86_64.pkg.tar.xz
yaourt-git-20111025-1-any.pkg.tar.xz
package-query-git-20111025-1-x86_64.pkg.tar.xz.sig
yaourt-git-20111025-1-any.pkg.tar.xz.sig
$ repo-add -s mon_depot.db.tar.gz *.xz
==> Ajoute le paquet 'package-query-git-20111025-1-x86_64.pkg.tar.xz'
  -> Calcul des sommes de contrôle…
  -> Ajout de la signature des paquets…
  -> Création de l'entrée 'desc'...
  -> Création de l'entrée 'depends'...
==> Ajoute le paquet 'yaourt-git-20111025-1-any.pkg.tar.xz'
  -> Calcul des sommes de contrôle…
  -> Ajout de la signature des paquets…
  -> Création de l'entrée 'desc'...
  -> Création de l'entrée 'depends'...
==> Création du nouveau fichier de dépôt 'mon_depot.db.tar.gz'
==> Signature de la base de données…

Vous avez besoin d'une phrase de passe pour déverrouiller la
clé secrète pour l'utilisateur: « tuxce  »
clé de 2048 bits RSA, ID EB671452, créée le 2011-10-25

  -> Le fichier mon_depot.db.tar.gz.sig des signatures a été créé.
$ ls
mon_depot.db
mon_depot.db.tar.gz
package-query-git-20111025-1-x86_64.pkg.tar.xz
yaourt-git-20111025-1-any.pkg.tar.xz
mon_depot.db.sig
mon_depot.db.tar.gz.sig
package-query-git-20111025-1-x86_64.pkg.tar.xz.sig
yaourt-git-20111025-1-any.pkg.tar.xz.sig

Rajout du dépôt à /etc/pacman.conf :

[mon_depot]
Server = file:///home/test/repo

Synchronisation :

# pacman -Sy
Avertissement : database file for 'mon_depot' does not exist
:: Synchronisation des bases de données de paquets...
 testing est à jour ;
 core est à jour ;
 extra est à jour ;
 community-testing est à jour ;
 community est à jour ;
 mon_depot                                     1548,0   B   998K/s 00:00 [#########################################] 100%
 mon_depot.sig                                  286,0   B   150K/s 00:00 [#########################################] 100%
Erreur : mon_depot: key "C2B09F4BEB671452" is unknown
:: Importation de la clé PGP EB671452, « tuxce  », 2011-10-25 créée ? [O/n] 

Si vous avez mis TrustAll et que votre clé est disponible sur le serveur de clé configuré (cf wiki / pacman-key), il suffit de répondre « o », sinon, il faudra d’abord importer la clé (que vous auriez par exemple exporté avec gpg --export) :

# pacman-key -a cle_publique.key
==> Mise à jour de la base de données de confiance…
gpg: vérification de la base de confiance inutile

Si pacman-key ne possède pas la clé ou si la vérification échoue, pacman retourne :

Erreur : la base de donnée 'mon_depot' n'est pas valide (base de données invalide ou corrompue (Signature PGP))

L’utilisation est transparente :

# pacman -S yaourt-git package-query-git

En plus de la vérification des paquets et des dépôts, pacman 4.x par le biais de makepkg permet en plus de pouvoir vérifier les sources des paquets soumis à AUR pour peu que l’auteur fournisse un .sig ou .asc, il suffira alors de le spécifier dans le PKGBUILD :

sources=(http://example.org/$pkgname-$pkgver.tar.gz{,.sig})

Voilà, en espérant que la transition se passera sans soucis.


Pacman Package Signing – 1, 2 et 3 d’Allan McRae
Historique par Dan McGee
pacman-key sur le wiki .fr.
GNU/Linux, Informatique | | Lien permanent | Commentaires (0)

Gnome Shell Extensions, modifier la zone de statut

Gnome est sorti il y a peu en version stable, la 3.0 et le peu qu’on puisse dire, c’est que ça en fait du changement. Certains sont pour, d’autres contre, mais peu importe, au final, ça a tendance à s’équilibrer et chacun y trouve son compte. Ceci dit, ce nouveau Gnome nous vient avec une interface/gestionnaire de fenêtre, Gnome Shell dont une grande partie du code est écrite en Javascript et utilisant du CSS pour le design. Ce dernier fournit également un système d’extensions qui, combinés au fait que c’est du Javascript donne une certaine liberté de configuration (si on connaît un peu de Javasciprt).

Revenons à Gnome Shell, ce dernier a une zone de statut (qui remplace l’ancienne zone de notification qui elle se retrouve en bas et cachée :|) dont une des icônes a tendance à m’agacer, celle nommée « accès universel » (déjà, je ne comprend pas le nom). Cette zone n’est pas configurable, je me fais une raison et en profite pour voir de plus près ces possibilités de modifications de Gnome Shell.

Tout d’abord, une des premières pages visitées donne une liste assez intéressante des possibilités de Gnome Shell, entre autre, la console Javascript (et un peu plus) intégrée qu’on peut lancer avec: Alt+F2 puis: lg

En cliquant sur la pipette (en haut à gauche), puis sur l’icône « accès universel », on a 2 lignes qui se rajoutent dans la console:

>>> <inspect x:901 y:18>
r(0) = [0x953d340 StBin.panel-button]

En cliquant sur le résultat (le 0×9…), on peut inspecter l’objet et entre autre voir qu’il y a 2 fonctions aux noms assez évocateurs, hide() et show(). Il n’y a plus qu’à tester:

>>> r(0).hide()
r(2) = undefined

L’icône a disparu; parfait. Et il se trouve que vous pouvez inspecter tout objet affiché.

Ceci dit, c’est bien beau, mais comment rendre ça permanent ? Il est temps de jeter un coup d’oeil aux extensions.

Gnome Shell fournit un outil pour créer une extension:

$ gnome-shell-extension-tool --create
 
Name should be a very short (ideally descriptive) string.
Examples are: "Click To Focus",  "Adblock", "Shell Window Shrinker".
 
Name: test
 
Description is a single-sentence explanation of what your extension does.
Examples are: "Make windows visible on click", "Block advertisement popups"
              "Animate windows shrinking on minimize"
 
Description: pour tester
 
Uuid is a globally-unique identifier for your extension.
This should be in the format of an email address (foo.bar@extensions.example.com), but
need not be an actual email address, though it's a good idea to base the uuid on your
email address.  For example, if your email address is janedoe@example.com, you might
use an extension title clicktofocus@janedoe.example.com.
Uuid [test@host]: test@home.lan
Created extension in '/home/test/.local/share/gnome-shell/extensions/test@home.lan'
$

Cet utilitaire crée un répertoire sous $XDG_DATA_HOME/gnome-shell/extensions contenant:

  • metadata.json : Informations sur votre extension.
  • stylesheet.css : Design de votre extension
  • extension.js : Le code à proprement dit.

extension.js contient déjà du code, c’est un exemple. Pour voir ce que ça fait: Alt+F2 puis r (juste « r »), puis cliquez sur le panel, Gnome Shell devrait vous dire bonjour.

Bien, mais c’est pas ce qu’on veut, voyons voir comment ça fonctionne…

  • Gnome Shell charge l’extension puis exécute la fonction main()
  • Les éléments de l’interface sont accessibles depuis l’objet imports.ui qui correspond au répertoire js/ui de l’installation de Gnome shell. Sous Archlinux : /usr/share/gnome-shell/js/ui

En jetant un coup d’oeil au fichier /usr/share/gnome-shell/js/ui/panel.js, on remarque la présence d’une constante:

const STANDARD_TRAY_ICON_ORDER = ['a11y', 'display', 'keyboard', 'volume', 'bluetooth', 'network', 'battery'];

En fait, ça correspond aux icônes de statut dans l’ordre d’apparition (si elles sont disponibles) et a11y correspond à l’icône accès universel (a .. 11 lettres .. y pour accessibility). Pour chaque icône, il existe une implémentation définie dans le même fichier:

const STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION = {
    'a11y': imports.ui.status.accessibility.ATIndicator,
    'volume': imports.ui.status.volume.Indicator,
    'battery': imports.ui.status.power.Indicator,
    'keyboard': imports.ui.status.keyboard.XKBIndicator
};

Modifions extension.js :

const Panel = imports.ui.panel;
function main() {
	Panel.STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION['a11y'] = false;
}

Les extensions se chargeant avant la construction de la zone de statut, cette dernière sera chargée sans cette icône.

Le but de départ est atteint, mais ça fait peu pour une extension (qui modifie une constante en plus). Quitte à découvrir, je me suis dit pourquoi ne pas aussi modifier l’ordre d’apparition des icônes et de fil en aiguille, j’ai fait une extension un peu plus conséquente: gnome-shell-msa

L’archive contient un PKGBUILD et les fichiers composant l’extension:

wget http://tuxce.no-ip.org/~tuxce/archlinux/gnome-shell/gnome-shell-msa-1-1.src.tar.gz
tar xzxvf gnome-shell-msa-1-1.src.tar.gz
cd gnome-shell-msa-1-1
makepkg -i

Elle a besoin d’être installée parce que pour le moment, je n’ai pas trouvé comment faire accepter à GSettings un schéma en dehors de /usr/share/glib-2.0/schemas.

Redémarrer gnome-shell.

Quelques essais:

# Placer le bluetooth et la batterie en premiers
gsettings set org.gnome.shell.extensions.msa icon-order "['bluetooth', 'battery']"
# Cacher l'accès universel
gsettings set org.gnome.shell.extensions.msa icons-hide "['a11y']"
# Remttre à 0
gsettings reset org.gnome.shell.extensions.msa icons-hide
gsettings reset org.gnome.shell.extensions.msa icons-order
# Désactiver l'icône de l'accès universel (nécessite un redémarrage de gnome-shell)
gsettings set org.gnome.shell.extensions.msa icons-disable "['a11y']"

L’extension était juste un moyen de voir un peu ce que permet Gnome Shell, et étant donné qu’une extension contient un fichier metadata.json contenant la version exacte de Gnome Shell, elle sera périmée dès la première mise à jour.


La documentation n’étant pas si simple à trouver, voici les ressources que j’ai utilisé:

  • Musings of an OS plumber, un ensemble d’article couvrant la personalisation de Gnome Shell
  • API Gjs. Il existe 2 implémentation Javascript sous Gnome Seed étant l’implémentation Javascript basée sur le moteur Webkit alors que Gjs est basé sur SpiderMonkey, Gnome n’a pas encore tranché entre les deux même si Gnome Shell utilise Gjs.
  • gnome-shell-extensions qui sont disponibles sur AUR pour Archlinux.
  • Les fichiers sources de gnome-shell, js/ui
  • + l’ensemble des liens de l’article

Fuseaux horaire sous GNU/Linux.

A l’origine, un fuseau horaire est une zone géographique avec une heure unique, ceci dit, pour des raisons propres (ou communes), un pays peut avoir son propre fuseau horaire qui de plus change au cours de l’année pour des questions d’économie d’énergie (DST: Day light saving time).

GNU/Linux utilise le fichier /etc/locatime pour connaître le fuseau horaire en fonction sur le système. Ce fichier est souvent une copie ou lien vers un fichier de la base de données tzdata fourni par le paquet du même nom (sous la plupart des distributions).

Ces fichiers ne sont pas lisibles, mais on peut avoir des informations dessus avec l’utilitaire zdump:

$ zdump /etc/localtime /usr/share/zoneinfo/Europe/Paris /usr/share/zoneinfo/Europe/London 
/etc/localtime                     Sun Oct 31 20:44:43 2010 CET
/usr/share/zoneinfo/Europe/Paris   Sun Oct 31 20:44:43 2010 CET
/usr/share/zoneinfo/Europe/London  Sun Oct 31 19:44:43 2010 GMT

On peut aussi avoir la liste des changements d’heure selon le fuseau horaire:

$ zdump -v /usr/share/zoneinfo/Europe/Paris | grep 2010
/usr/share/zoneinfo/Europe/Paris  Sun Mar 28 00:59:59 2010 UTC = Sun Mar 28 01:59:59 2010 CET isdst=0
/usr/share/zoneinfo/Europe/Paris  Sun Mar 28 01:00:00 2010 UTC = Sun Mar 28 03:00:00 2010 CEST isdst=1
/usr/share/zoneinfo/Europe/Paris  Sun Oct 31 00:59:59 2010 UTC = Sun Oct 31 02:59:59 2010 CEST isdst=1
/usr/share/zoneinfo/Europe/Paris  Sun Oct 31 01:00:00 2010 UTC = Sun Oct 31 02:00:00 2010 CET isdst=0

GNU/linux utilise une horloge système et une matérielle (celle du BIOS).

$ hwclock --debug
hwclock de util-linux-ng 2.18
Utilisant /dev interface to clock.
Le dernier ajustement de dérive a été fait 1288551786 secondes après 1969
La dernière calibration a été faite 1288300319 secondes après 1969
L'horloge matérielle fonctionne selon le temps UTC
On assume que l'horloge matérielle est conservée dans le temps de UTC.
En attente d'un tic d'horloge...
...a obtenu un tic d'horloge
Heure lu de l'horloge matérielle: 2010/10/31 19:06:52
Heure de l'horloge matérielle : 2010/10/31 19:06:52 = 1288552012 secondes depuis 1969
dim. 31 oct. 2010 20:06:52 CET  -0.307298 secondes

Si elle est configurée comme étant le temps universel (UTC), le résultat d’une demande d’heure est en fait l’heure UTC + le décalage du fuseau, donc du moment que le fichier /etc/localtime est bien configuré, le système suivra les changements d’heure sans souci.

Par contre, si votre horloge matérielle est configurée pour correspondre à l’heure locale, le système ne fait pas grand chose et le changement d’heure ne se fait pas automatiquement. Mais comme on règle l’heure matérielle sur l’heure locale seulement quand on a un Microsoft Windows en dual boot, l’heure sera réglée par ce dernier.

Sinon il faut le faire manuellement:

date 10312008

Et comme le système garde une trace du décalage de l’heure matérielle, il serait bon de la régler pour ne pas faire croire au système que le matériel dérive d’une heure:

hwclock --noadjfile --localtime -w

Soumis au bon vouloir de ConsoleKit.

Pour ceux à qui ConsoleKit ne dit rien du tout, vous pouvez vous référer aux pages wiki archlinux.fr (les explications étant génériques): wiki consolekit.

En bref, ConsoleKit s’occupe de traquer l’état des sessions de l’utilisateur en suivant des données parmi lesquelles:

  • l’état actif de la session.
    ex: vous avez lancé X et avez changé vers un terminal (ctrl-alt-f1), votre session X n’est plus active.
  • l’emplacement de la session
    ex: une connexion depuis ssh n’est pas « locale ».

Ces deux informations influencent directement toutes les actions sur les périphériques (si gérés par des programmes compatibles), par exemple, PCManFm ou Nautilus passent par PolicyKit (wiki) pour savoir s’ils ont la permission de monter un périphérique ou pas.

Cette introduction pour dire qu’à partir de la version 0.4.2 de ConsoleKit, qui est notamment celle disponible sur le dépôt [testing] d’Arch Linux, la détection d’une session locale change de méthode.

Avant, c’était plus en devinant que le programme déterminait l’état « locale » ou non de la session, il suffisait d’avoir un:

exec ck-launch-session openbox-session
# ou autre environnement de bureau

dans le $HOME/.xinitrc, et suite au startx, la session était locale et les droits étaient donnés à l’utilisateur.

A partir de la 0.4.2, seul le root peut définir l’état « locale », et adieu les permissions pour les utilisateurs n’utilisant pas de gestionnaire de connexions compatibles tel GDM. PCManFm ou Nautilus nous sortent une belle fenêtre « Not authorized » à chaque tentative de montage.

La solution consiste à ajouter un connecteur PAM pour que ce soit le root qui crée la session en lui donnant pour le coup le bon état.

Pour une connexion depuis le terminal (par le programme « login »), il faut avoir:

session		optional	pam_ck_connector.so

dans /etc/pam.d/login.

Si vous utilisez un gestionnaire de connexions tel que SLiM, il faut faire pareil dans /etc/pam.d/slim.


FS#21391

Page forum archlinux.fr sur votre mobile

Suivant pas mal le forum archlinux.fr, il m’arrive de vouloir y accéder depuis mon mobile, mais le format de la page est tout sauf compatible avec un mobile, alors pour faire simple, j’ai fait un petit script de pas grand chose pour afficher la liste des derniers posts accessible ici

Source: archforum.php

Installer un paquet Arch linux directement depuis firefox

C’est sûrement le genre de chose qui va finir aux oubliettes parce qu’il va être utilisé qu’une fois, mais peu importe, c’est aussi par curiosité.

De temps en temps, après une mise à jour à problème comme celle d’autoconf 2.66 actuellement, je voudrais réinstaller l’ancienne version du paquet, en théorie, il suffit d’aller dans le cache: /var/cache/pacman/pkg, mais si on l’a effacé, il faut se rabattre sur l’une des méthodes décrites dans le wiki. J’avais fait un script il y a longtemps pour revenir en arrière, mais encore faut il connaître la date du dernier paquet voulu.

Une autre méthode est de naviguer sur http://arm.kh.nu/ puis télécharger, lancer pacman etc…

Pour automatiser le téléchargement et lancement de pacman, je vais créer un protocole du genre d’apt:// et utiliser le script greasemonkey suivant:

// ==UserScript==
// @name           Pacman package
// @namespace      http://tuxce.no-ip.org
// @description    Install a pacman package
// @include        http://arm.kh.nu/*
// ==/UserScript==
 
var allElements, thisElement;
allElements = document.getElementsByTagName('a');
pkg_re=/\.pkg\.tar\./
for (var i = 0; i < allElements.length; i++) {
	thisElement = allElements[i];
	if (thisElement.href.match (pkg_re))
	{
		var a_custom = document.createElement('a');
		a_custom.setAttribute ('href', 'pacman://' + thisElement.href);
		a_custom.appendChild (document.createTextNode ('#'));
		thisElement.parentNode.insertBefore (a_custom, thisElement);
		thisElement.parentNode.insertBefore (document.createTextNode(' '), thisElement);
		i++;
	}
}

Cliquer sur le lien suivant pour l’installer si vous avez Greasemonkey: pacman_package.user.js

On crée un script pour prendre en charge l’url:

#!/bin/bash
 
urxvtc -e sudo pacman -U "${1:9}"

urxvtc -e à modifier selon le terminal que vous utilisez.

Il ne reste plus qu’à ajouter la prise en compte du protocole par firefox:

gconftool-2 -s -t string /desktop/gnome/url-handlers/pacman/command "chemin_vers_le_script '%s'"
gconftool-2 -s -t boolean /desktop/gnome/url-handlers/pacman/enable true

Aller sur http://arm.kh.nu/, si vous avez Greasemonkey d’activé, vous devriez voir apparaître « #  » devant chaque paquet, cliquez sur celui que vous voulez, au premier clic, il faudra donner le script avec lequel firefox gérera le lien, et c’est bon.

Trouver les capacités (capabilities) d’un programme

Suite à l’article précédent sur les capacités POSIX, il restait une question en suspens. Pouvoir trouver les capacités nécéssaire à un programme; pour cela, on peut utiliser la capacité qu’offre le noyau pour « court circuiter » des fonctions: Kernel Probes

Le principe est simple si on connaît la fonction appellée, on crée un module ayant une fonction similaire (même prototype) qui log les demandes de capacités selon un nom de programme passé en paramètre au module. Ce dernier nécessite que le noyau ait certaines options d’activées (CONFIG_KPROBES, CONFIG_KALLSYMS_ALL, CONFIG_KALLSYMS entre autres) ce qui n’est pas le cas par défaut sur Arch Linux par exemple, vous pouvez télécharger une version modifiée du PKGBUILD du paquet kernel26 version 2.6.32.7-1: kernel26-2.6.32.7-1.src.tar.gz

Le module est celui de l’article de Serge E. Hallyn [1], j’y ai juste rajouté le paramètre pour le nom du programme à surveiller ainsi qu’un tableau pour me sortir directement la capacité en texte.
Archive: capable_probe.tar.gz
capable_probe.c:

// Original taken from http://www.ibm.com/developerworks/library/l-posixcap.html
// By Serge E. Hallyn (sergeh at us.ibm.com)
//
// Modified by tuxce <tuxce.net at gmail.com>
//
 
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/sched.h>
 
 
 
static char progname[255];
module_param_string(progname, progname, sizeof(progname), 0644);
MODULE_PARM_DESC(progname, "Program name.");
 
static const char *probed_func = "cap_capable";
 
static char *cr_cap[] = { "CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", 
	"CAP_FOWNER", "CAP_FSETID", "CAP_KILL",
	"CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", 
	"CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", 
	"CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", 
	"CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", 
	"CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", 
	"CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", 
	"CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", 
	"CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", 
	"CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", 
	"CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN" };
 
int cr_capable (struct task_struct *tsk, const struct cred *cred, int cap, 
	int audit)
{
	if(strcmp(tsk->comm,progname) == 0)
		if (cap >=0 && cap <= 33)
		{
			printk(KERN_NOTICE "%s: asking for capability %s for %s\n",
				__FUNCTION__, cr_cap[cap], tsk->comm);
		}
		else
		{
			printk(KERN_NOTICE "%s: asking for capability %d for %s\n",
				__FUNCTION__, cap, tsk->comm);
		}
	jprobe_return();
	return 0;
}
 
static struct jprobe jp = {
	.entry = JPROBE_ENTRY(cr_capable)
};
 
static int __init kprobe_init(void)
{
	int ret;
	jp.kp.symbol_name = (char *)probed_func;
 
	if ((ret = register_jprobe(&jp)) < 0) {
		printk("%s: register_jprobe failed, returned %d\n",
			__FUNCTION__, ret);
		return -1;
	}
	return 0;
}
 
static void __exit kprobe_exit(void)
{
	unregister_jprobe(&jp);
	printk("capable kprobes unregistered\n");
}
 
module_init(kprobe_init);
module_exit(kprobe_exit);
 
MODULE_LICENSE("GPL");

Makefile:

# Taken from http://www.ibm.com/developerworks/library/l-posixcap.html
obj-m := capable_probe.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
install: default
	install -d /lib/modules/$(shell uname -r)/kernel/misc/
	install capable_probe.ko /lib/modules/$(shell uname -r)/kernel/misc/
	depmod -a
clean:
	rm -f *.mod.c *.ko *.o

On compile:

$ make
make -C /lib/modules/2.6.32-ARCH/build SUBDIRS=/home/tuxce/posix/capable modules
make[1]: entrant dans le répertoire « /usr/src/linux-2.6.32-ARCH »
  CC [M]  /home/tuxce/posix/capable/capable_probe.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/tuxce/posix/capable/capable_probe.mod.o
  LD [M]  /home/tuxce/posix/capable/capable_probe.ko
make[1]: quittant le répertoire « /usr/src/linux-2.6.32-ARCH »
$ sudo insmod capable_probe.ko progname=ping

Si tout se passe bien, vous devrez pouvoir récuperer les capacités demandées dans le log, /var/log/messages.log pour Arch Linux:

$ ping -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.064 ms
 
--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.064/0.064/0.064/0.000 ms
$ tail -2 /var/log/messages.log
Feb  8 17:30:44 host kernel: cr_capable: asking for capability CAP_NET_RAW for ping
Feb  8 17:30:44 host kernel: cr_capable: asking for capability CAP_SETUID for ping

Dans le log, on voit que ping demande CAP_NET_RAW (qu’on a utilisé dans l’exemple de l’article précédent), de même que CAP_SETUID, cette dernière est utilisée pour passer de root à l’utilisateur exécutant la commande, mais comme on a supprimé le setuid, ce n’est plus nécessaire.

L’utilisation du module est assez simple, ou bien on le décharge puis charge avec le bon paramètre, ou on modifie le paramètre en cours de fonctionnement:

sudo cp /usr/bin/crontab{,.x}
echo -n crontab.x | sudo tee /sys/module/capable_probe/parameters/progname
crontab.x -e

Et voyons voir ce que demande crontab:

Feb  8 18:18:33 host kernel: cr_capable: asking for capability CAP_SETGID for crontab.x
Feb  8 18:18:33 host kernel: cr_capable: asking for capability CAP_DAC_OVERRIDE for crontab.x
Feb  8 18:18:33 host kernel: cr_capable: asking for capability CAP_DAC_OVERRIDE for crontab.x

Là, on a exécuté la commande "crontab -e" car elle demande plus de privilèges que par exemple "crontab -l".
Selon la sortie du log, pour se débarasser du setuid de crontab:

sudo setcap CAP_DAC_OVERRIDE,CAP_SETGID=ep crontab



Ressources:
POSIX file capabilities: Parceling the power of root

Posix Capabilities

Donner plus ou moins de privilèges à un utilisateur a et est toujours un casse tête sur un système d’exploitation. Autant, le fait que certaines actions nécessitent d’être root ne gène pas, autant certaines autres, la plupart du temps effectués par l’utilisateur, font paraître le passage en root comme une action supplémentaire superflue.

La méthode classique est d’avoir ces programmes en setuid root (+s):

$ ls -al /bin/ping
-rwsr-xr-x 1 root root 31020  4 oct.   2008 /bin/ping

Le souci, c’est qu’une vulnérabilité de ping peut devenir problèmatique, les Posix Capabilities permettent d’affiner un peu plus les droits donnés à un programme.

Installons tout d’abord le paquet fournissant les outils nécessaires, sous Arch Linux:

pacman -S libcap

Faisons un essai:
Copions l’exécutable (il perd son setuid lors de la copie):

sudo cp /bin/ping /bin/ping.x

Un test échouera au vu du manque de permission:

$ ping.x -c 1 127.0.0.1
ping: icmp open socket: Operation not permitted

Rajoutons à l’exécutable la capacité CAP_NET_RAW (en root)

sudo setcap cap_net_raw=ep /bin/ping.x

Un autre essai:

$ ping.x -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.064 ms
 
--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.064/0.064/0.064/0.000 ms

Les capacités disponibles sont détaillées dans man capabilities.
Les capacités peuvent être assignées à un processus et/ou un fichier (exécutable) en trois ensembles:

  • Permises (p): Capacités pouvant être acquises
  • Héritées (i): Capacités léguées
  • Effectives (e): Capacités acquises

En partant de ces trois ensembles, les capacités sont calculées pour chaque processus selon la logique suivante:

'=capacités calculées
p=capacités du processus
f=capacités du fichier
I=héritées, P=permises, E=effectives
 
pI' = pI
pP' = fP | (fI & pI)
pE' = pP' & fE

Un processus ne peut utiliser une capacité que si elle existe dans l’ensemble permis et effectif (d’où le "ep" sur l’exemple du ping.x)

Imaginons qu’on veuille restreindre le ping à certains utilisateurs, on a besoin de la capacité "cap_net_raw=ep" mais seulement à l’exécution de ping. D’après la logique de calcul:

  • ping.x doit avoir "cap_net_raw=ie"
  • Le processus appelant ping.x doit avoir "cap_net_raw=i"

Ainsi, pP' et pE' auront tous deux cap_net_raw.

Un test:

$ sudo setcap -r /bin/ping.x
$ getcap -v /bin/ping.x
/bin/ping.x
$ sudo setcap cap_net_raw=ie /bin/ping.x
$ getpcaps $$
Capabilities for `6263': =
$ ping.x -c 1 127.0.0.1
ping: icmp open socket: Operation not permitted
$ sudo capsh --caps="cap_net_raw=i" -- -c "su - $USER"
$ getpcaps $$
Capabilities for `6350': = cap_net_raw+i
$ ping.x -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.048 ms
 
--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.048/0.048/0.048/0.000 ms
$

Là, on a exécuté un shell en lui affectant une capacité (en utilisant le root), mais si on doit faire ceci à chaque fois, ça ne sert pas à grand chose… Ça tombe bien, c’était juste pour tester la faisabilité, voyons voir comment donner des permissions à un utilisateur.

Les capacités sont héritées par les processus fils, il suffit donc de doter le premier processus lancé par l’utilisateur des capactiés voulues, c’est là que rentre en action PAM [1] le module d’authentification sous linux.

Le paquet libcap sous Arch Linux apporte un module nommé pam_cap.so permettant de configurer ceci. Dans /etc/security/capability.conf:

cap_net_raw	tuxce
none *

Il faut aussi rajouter le module en question dans la configuration pam, /etc/pam.d/login:

auth		required	pam_cap.so

On teste en se loguant depuis une console texte:

host login: tuxce
Password: 
Last login: Tue Feb  9 14:08:55 CET 2010 on pts/2
[tuxce@host ~]$ getpcaps $$
Capabilities for `7601': = cap_net_raw+i
[tuxce@host ~]$ logout

Une alternative à pam_cap.so serait d’utiliser un soft comparable à sudo mais spécifique aux capacités, ça tombe bien, un des développeurs d’Arch Linux, Thomas Bächler alias brain0 a developpé l’outil capsudo qui permet en le configurant d’attribuer des droits à certains utilisateurs [2].

Vous pouvez télécharger le PKGBUILD suivant: capsudo-git-20100209-1.src.tar.gz
En prenant toujours l’exemple de ping, rajoutons ce qui suit à /etc/capsudoers:

[ping.x]
	command = /bin/ping.x
	allow_user_args = true
	caps = cap_net_raw
	users = tuxce

Assurons nous que /bin/ping.x ait "cap_net_raw+ei", puis:

$ capsudo ping.x -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.045 ms
 
--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.045/0.045/0.045/0.000 ms

Voilà, avec un mélange de tout ceci, on devrait être capable de donner des droits plus restreints aux exécutables sans pour autant leur permettre de prendre l’identité du root.

Reste la difficulté de deviner les capacités qu’il faut pour les programmes, deux possibilités, écumer le net pour trouver les capacités utilisées par tel ou tel programme, ou bien utiliser un module (nécéssitant certaines options du noyau) qui permet de logguer les demandes d’autorisations, ça fera l’objet d’un autre article, vous pouvez vous référer au wiki anglophone sur les capacités pour une liste non exhaustive.




Ressources:
Petite introduction à PAM (Artisan Numérique)
POSIX file capabilities: Parceling the power of root
Linux kernel capabilities FAQ
Using POSIX capabilities in Linux, part two (brain0)

Archlinux, un live CD/USB non figé.

Il faut avoir lu le wiki pour créer un live d’Archlinux (ou savoir comment faire) pour suivre cet article.

AUFS est un système de fichier permettant d’unifier plusieurs répertoires en un seul, c’est une réécriture d’unionfs 1.x

Certains projets propres à Archlinux l’utilisent comme par exemple devtools (makechrootpkg qui permet de construire un paquet dans un chroot) ou encore archiso (création d’un live).

AUFS permet donc de fusionner plusieurs répertoires en un seul, la priorité étant donnée au premier dans la liste si deux fichiers portent le même nom; par défaut, le premier répertoire de la liste est en lecture/écriture et le reste est en lecture seule, tout ajout ou modification sont répercutés sur le premier répertoire.
Voyons voir un exemple en prenant l’arborescence suivante:

# tree
.
|-- a
|   |-- fichier_1
|   `-- fichier_2
|-- b
|   |-- fichier_1
|   `-- fichier_3
|-- c
`-- result
 
4 directories, 4 files
# more a/fichier_1 b/fichier_1 
::::::::::::::
a/fichier_1
::::::::::::::
1
::::::::::::::
b/fichier_1
::::::::::::::
2

Montons a/ et b/ dans result/:

mount -t aufs -o br:a=ro:b none result/

On le monte en lecture seule, ça nous donne comme résultat:

# tree result
result
|-- fichier_1
|-- fichier_2
`-- fichier_3
 
0 directories, 3 files
# cat result/fichier_1 
1

Ainsi, on se retrouve avec l’ensemble des fichiers et comme fichier_1 était en double, le premier répertoire (a/) a la priorité.

Maintenant, disons, qu’on veut modifier un élément, comme le répertoire est monté en lecture seule, on ne peut pas, il suffit pour y remédier de changer ou rajouter une branche en lecture/écriture:

# mount -t aufs -o remount,prepend:c none result/
# echo 4 > result/fichier_1
# umount result/
# cat c/fichier_1 
4
# cat a/fichier_1 
1
# cat b/fichier_1 
2

On a modifié le contenu de result/fichier_1, ce qui a laissé intact les fichiers du même nom sur a/ et b/ mais a créé un nouveau fichier dans la branche avec possibilité d’écriture : c/.

C’est exactement le même principe qui est appliqué au liveCD servant à l’installation d’Archlinux ou tout autre live construit avec archiso (en tout cas, jusqu’à cet instant), une partition tmpfs est monté en premier, ainsi, on peut écrire, les différentes couches composant le live sont montées par la suite.

Au cas où, on peut avoir des informations sur un répertoire monté avec AUFS dans /sys/fs/aufs/si_X:

# mount -l -t aufs
none on /tmp/aufs_test/result type aufs (rw,relatime,si=f55ed40b26bb76b5)
# cat /sys/fs/aufs/si_f55ed40b26bb76b5/br*
/tmp/aufs_test/c=rw
/tmp/aufs_test/a=ro
/tmp/aufs_test/b=ro

Partant de là et en supposant que vous avez lu le wiki pour créer un live d’Archlinux, créons un live qui ne sera pas figé et qu’on peut un minimum personnaliser.

Le principe est simple, il nous faut une partition indépendante qui fera office de couche lecture/écriture pour notre live, pour la détecter et l’utiliser, on va se baser sur la méthode de détection du support par le hook archiso, lors de la création du live, une étiquette est donnée à l’image iso créée et cette étiquette est fournie comme paramètre du noyau dans la configuration de isolinux:

append initrd=/boot/archiso.img  lang=fr locale=fr_FR.UTF-8 ramdisk_size=75% archisolabel=ARCH_201001

(par défaut, l’étiquette est ARCH_ + année + mois)

On choisit par exemple rootrw comme étiquette à donner à notre partition et le paramètre rootlabel pour le noyau.
Prenons le cas le plus simple, une clé usb reconnue en tant que /dev/sdb dont on va utiliser la première partition préalablement créée:

mkfs.ext2 -L rootrw /dev/sdb1

C’est censé être du live, ext2 est largement suffisant.

La détection et le montage de la racine se fait dans les hooks archiso-early et archiso, modifions un peu ces hooks pour détecter notre partition, le patch (par rapport à ce commit): archiso_rootrw.patch
Le patch peut sûrement être meilleur, mais là, en pleins dans les phases de tests, il fonctionne, c’est le principal.

Pour tester:

wget http://tuxce.no-ip.org/wp-content/uploads/2010/01/archiso-git-20100111-1.src.tar.gz
tar zxvf archiso-git-20100111-1.src.tar.gz
cd archiso-git
makepkg --skipinteg -i

Le PKGBUILD télécharge un snapshot d’archiso et ce dernier change le md5sum (une subtilité de cgit sûrement ou une histoire de timestamp, j’ai pas cherché), d’où le skipinteg.

Une fois cette version d’archiso installée, il nous faut modifier isolinux.cfg, recréer l’initrd et le .iso. En se basant sur le wiki, on rajoute les lignes suivantes à isolinux.cfg:

label perso
kernel /boot/vmlinuz26
append initrd=/boot/archiso.img  lang=fr locale=fr_FR.UTF-8 ramdisk_size=75% archisolabel=ARCH_201001 rootlabel=rootrw

On refait l’étape mkinitcpio puis on recrée l’image:

rm exemple.iso
mkarchiso iso traitement exemple.iso

On s’assure que la clé usb est insérée et on lance un qemu en démarrant sur l’entrée perso pour tester:

qemu-kvm -k fr -m 512 -hda exemple.iso -hdb /dev/sdb

Il n’y a plus qu’à faire des modifications et redémarrer l’image.

En théorie, le test devrait être concluant (en tout cas chez moi :)), mais ce qui serait mieux, c’est d’avoir le live et la partition de modification sur le même périphérique, en supposant que votre clé usb est reconnue en tant que /dev/sdb:

dd if=exemple.iso of=/dev/sdb
fdisk /dev/sdb << EOF
n
p
2
 
 
p
w
EOF
mkfs.ext2 -L rootrw /dev/sdb2

Ceci devrait être suffisant pour avoir un live pouvant être modifié.

Pour plus de détails n’hésitez pas à jeter un coup d’oeil aux scripts composant archiso, à mkarchroot (pour par exemple mettre à jour le live) ainsi qu’à man aufs