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.selfip.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.selfip.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

urxvt: modifier le fond pendant l’exécution

J’aime assez avoir de la vrai transparence sur un terminal, urxvt le permet, j’en profite. Par contre, quand des fenêtres s’entassent comme ça m’arrive trop souvent à mon goût, et que j’ouvre un fichier de configuration ou les sources d’un programmes, avec la colorisation, c’est tout simplement illisible…

Donc, là commence la recherche, il faut trouver comment modifier la configuration d’urxvt en cours de fonctionnement, je connaissais comment changer la police mais ça s’arrêtait là… Une recherche sur le net n’a pas donné grand chose, mais c’est sans compter sur les pages man :)

urxvt propose une page à la section 7:

man 7 urxvt

Cette dernière couplée avec celle par défaut répond à toute les questions sur la configuration, on y découvre (si ce n’est pas déjà connu), qu’il suffit d’utiliser les caractères d’échappement pour modifier certaines ressources.
La syntaxe est simple:

echo -e '\033]Ps;Pt\007'

Ps étant le code de la ressource à modifier et Pt la valeur, ainsi pour changer de fond d’écran:

# Fond noir opaque:
echo -e '\033]11;#000\007'
# Fond noir transparent à 80%:
echo -e '\033]11;[80]#000\007'

Reste plus qu’à mettre un raccourci, il suffit de rajouter deux ressources URxvt.keysym dans le ~/.Xdefaults:

URxvt.keysym.Control-t: command:\033]11;[80]#000\007
URxvt.keysym.Control-M-t: command:\033]11;#000\007

Ctrl-Alt-t enlève la transparence.
Ctrl-t la remet.

Il est bien ce urxvt quand même.

LDAP, Dovecot, fetchmail, procmail

Le but ici est de mettre en place un serveur imap avec une identification par serveur LDAP qui pourra éventuellement servir de carnet d’adresse partagé.
Le point de départ est un ensemble de compte mails hébergés sur un serveur qui ne propose malheureusement qu’un accès pop3.
Ça permet entre autre d’avoir un double des mails par rapport aux clients que peuvent avoir les utilisateurs ainsi que d’avoir une politique de sauvegarde (ça peut toujours servir), de partager un carnet d’adresses et même un ou des répertoires de mails.

Vu que je ne décris que la configuration minimum pour que ça fonctionne, il ne faut pas hésiter à pousser la recherche, notamment pour une définition plus poussée des droits d’accès à l’annuaire LDAP, je laisse celle par défaut ici.

Serveur d’authentification: LDAP
Serveur IMAP: Dovecot
Utilitaires de rapatriement des mails: fetchmail, procmail.

Commençons par installer et configurer openLDAP:

pacman -S openldap

Générons d’abord un mot de passe:

$ slappasswd 
New password: 
Re-enter new password: 
{SSHA}/lzUz+0mTGl9DGnG5XJQBdKxwaWNUSic

Configuration de /etc/slapd.conf:

include		/etc/openldap/schema/core.schema
include		/etc/openldap/schema/cosine.schema
include		/etc/openldap/schema/inetorgperson.schema
include		/etc/openldap/schema/misc.schema
include		/etc/openldap/schema/nis.schema
pidfile   	/var/run/slapd.pid
argsfile  	/var/run/slapd.args
database	bdb
suffix		"dc=home,dc=lan"
rootdn		"cn=admin,dc=home,dc=lan"
rootpw		{SSHA}/lzUz+0mTGl9DGnG5XJQBdKxwaWNUSic
directory	/var/lib/openldap/openldap-data
index	objectClass	eq

Peuplons un peu la base, test.ldif:

dn: dc=home,dc=lan
objectClass: domain
dc: home
 
 
dn: ou=people,dc=home,dc=lan
ou: people
objectClass: top
objectClass: organizationalUnit
 
 
dn: ou=group,dc=home,dc=lan
ou: group
objectClass: top
objectClass: organizationalUnit
 
 
dn: cn=dovecot, dc=home, dc=lan
objectClass: top
objectClass: person
objectClass: organizationalPerson
cn: dovecot
sn: dovecot
 
 
dn: uid=tuxce,ou=people,dc=home,dc=lan
uid: tuxce
cn: tuxce last name
givenName: tuxce
sn: tuxce
mail: tuxce@home.lan
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
displayName: tuxce
ldapadd -D 'cn=admin,dc=home,dc=lan' -x -W -f test.ldif

Définissons un mot de passe pour dovecot:

ldappasswd -D 'cn=admin,dc=home,dc=lan' -x -W -S 'cn=dovecot,dc=home,dc=lan'

On devrait déjà avoir un serveur utilisable, à chacun de configurer les droits d’accès selon son schéma.

Installation et configuration de Dovecot:
Sous archlinux, comme d’habitude:

pacman -S dovecot

Le serveur imap accueillera des comptes n’ayant pas forcément d’équivalent en terme de compte utilisateur sur le serveur, il nous faut donc utiliser des utilisateurs virtuels.

Dovecot devra utiliser un seul utilisateur que l’on va nommer vmail et les boîtes au lettres seront stockées dans son répertoire personnel:

useradd -s /bin/nologin -m -d /home/vmail -c 'Virtual Mail User' vmail

Modification de /etc/dovecot.conf (je n’indique ici que ce que j’ai modifié):

mail_location=maildir:/home/vmail/%u
mail_uid = vmail
mail_gid = vmail
auth default {
  mechanisms = plain
  passdb ldap {
    args = /etc/dovecot/dovecot-ldap.conf
  }
  userdb ldap {
    args = /etc/dovecot/dovecot-ldap.conf
  }
}

Modification de /etc/dovecot/dovecot-ldap.conf:

hosts = localhost
dn = cn=dovecot,dc=home,dc=lan
dnpass = test
auth_bind = yes
auth_bind_userdn = uid=%u,ou=people,dc=home,dc=lan
ldap_version = 3
base = ou=people, dc=home, dc=lan
scope = subtree
 
user_filter = (&(objectClass=organizationalPerson)(uid=%u))
 
pass_attrs = uid=user,userPassword=password
pass_filter = (&(objectClass=organizationalPerson)(uid=%u))

Passons maintenant à la configuration de fetchmail et procmail:

pacman -S fetchmail procmail

Pour accéder au compte vmail vu que je l’ai crée avec le shell /sbin/nologin:

su - -s /bin/bash vmail

Création de .procmailrc:

PMDIR=/home/vmail
MAILDIR="$PMDIR/$1/"
LOGFILE=$PMDIR/procmail.log
VERBOSE=on
 
:0
"$MAILDIR"

Création de .fetchmailrc:

set daemon 1200 # 20 mn
set logfile fetchmail.log
set invisible
set bouncemail
 
poll "pop.exemple.org" protocol pop3 
user "tuxce@exemple.org" password "toto" mda "/usr/bin/procmail -a tuxce"
# Pour tester, je vous conseille d'utiliser la ligne suivante:
#user "tuxce@exemple.org" password "toto" keep mda "/usr/bin/procmail -a tuxce"
# Histoire de pas de se retrouver avec des mails perdus

Démarrage des serveurs et test:

/etc/rc.d/slapd start
/etc/rc.d/dovecot start
su - vmail -c "fetchmail"

Il ne reste plus qu’à configurer un client imap et à rafraîchir l’arborescence.

WordPress: résultat de recherche / 404

Après des migrations, des changements de styles, de configurations ou autre, il peut arriver que les articles d’un blog ne soient plus au même endroit qu’avant. Le but, bien sûr, est d’avoir le moins de changement possibles, mais certaines fois, c’est nécessaire et l’astuce suivante peut tout aussi servir pour ceux qui tapent une mauvaise adresse web.

Le principe est de rediriger toute erreur 404 (page non trouvée) vers une recherche dont les termes correspondent au contenu de l’adresse, tout en envoyant quand même l’erreur.

Sous wordpress, cela se fait simplement en modifiant la page 404.php de votre thème:

<?php
// Renvoie l'erreur
@header("HTTP/1.1 404 Not found", TRUE, 404);
// décode l'url et ne prend que la dernière partie
$query = urldecode(stripslashes($_SERVER['REQUEST_URI']));
$query = trim (substr ($query, strrpos ($query, "/")+1));
// encode les termes de recherches
$query = urlencode ($query);
// définit le nombre de tentative de recherches
$tries=3;
// Boucle jusqu'à ne plus avoir de termes, qu'il y ait un résultat 
// ou qu'on ait épuisé le nombre de recherches
do
{
  query_posts('s=' . $query);
  $query = substr ($query, strpos ($query, "+")+1);
} while (!have_posts() and $query and $tries-->0);
include ("search.php");
?>

Exemple.

Récupérer des sites en flux RSS

Personnellement, j’utilise beaucoup les flux RSS pour suivre certains sites d’information, blogs ou forums, ça permet d’avoir un rapide coup d’œil sur ce qui pourrait m’intéresser, centralise le tout dans un seul logiciel et surtout ce logiciel s’occupe tout seul des mise à jours.

Malheureusement certains sites n’ont pas de flux, ou ne donnent que des versions courtes de leur articles, ce qui est leur choix, ça leur permet d’économiser la bande passante peut être ou oblige à passer sur leur site pour voir la pub qui va bien, alors bon je me suis pas vraiment posé la question (ou si mais j’y ai pas répondu) si j’avais le droit ou pas de passer outre la limitation, toujours est il que je le faisais au cas par cas, au bout de trois/quatre sites je me suis dit, essayons d’automatiser un peu tout ça.

Le principe est simple, le programme récupère une page avec la liste des articles et pour chacun d’entre eux, il récupère son adresse, télécharge sa page, récupère les informations telle que la date, l’auteur, le contenu à proprement dit et met le tout sous forme d’un fichier xml décrivant un flux RSS.

Cependant le principe a beau être simple, la sélection des informations se fait à l’aide d’expressions régulières et plus précisément à l’aide de sed, donc si vous y êtes réfractaires, ce qui va suivre peut choquer…

Alors, pour ceux qui sont restés, le script est configurable, chaque site correspond à un fichier qui définit comment récupérer les informations, pour l’exemple, je vais me baser sur le forum anglophone d’Archlinux qui ne propose pas de flux RSS.

EDIT: En fait, comme indiqué dans les commentaires, Archlinux utilisant un forum PunBB, ce dernier propose des flux, néanmoins, on n’a pas accès au contenu des posts, mais seulement aux titres des derniers sujets.

Nommons ce fichier arch.org:

# Fichier de configuration pour le flux du forum anglophone Archlinux.
RSS_URL="http://bbs.archlinux.org/"
BASE_URL="$RSS_URL/search.php?action=show_24h"
RSS_TITLE="Archlinux BBS"
RSS_DESCRIPTION="Archlinux BBS"
TZ_REMOTE="-0400"
SED_SELECT_URL=('/< \/tbody>/q' 's|.*\(viewtopic\?[^#]*#p[0-9]*\).*|'"$RSS_URL"'\1|p')
 
SED_ITEM_TITLE=('/&raquo;&nbsp;[^< ]\+<\/li>< \/ul>$/ { s/.*&raquo;&nbsp;\([^< ]\+\)<\/li>< \/ul>$/\1/p;q}')
SED_ITEM_AUTHOR=('/profile.php?/ { s|.*>\([^< ]*\)</a>.*|\1|p;q}')
SED_ITEM_DATE=('/<h2>.*viewtopic.php/ {s/.*>\([^< ]\+\).*<\/a.*/\1/p;q}')
SED_ITEM_CONTENT=('/class="postmsg"/,/<\/div>/ { /class="postmsg"/d;/^ *< \/div>/d; p}')
 
pre_post ()
{
	POST_ID=${1#*#}
	SED_SELECT_ITEM=('/&raquo;&nbsp;[^< ]\+<\/li>< \/ul>$/ { p }'
	'/<div id="'"$POST_ID"'"/,/^<\/div>/ { p }')
}
# La ligne suivante est là juste à cause du fait que wordpress rajoute des balises 
# (la flemme de chercher à contourner)
#</div></h2>

Je vais pas ici détailler les expressions, sachez néanmoins qu’elles sont exécutées à l’aide de:

sed -n -e expr1 -e expr2

Pour ce qui est des variables:

  • RSS_URL: adresse du site.
  • BASE_URL: adresse de la page regroupant les articles (les derniers posts en ce qui concerne l’exemple)
  • RSS_TITLE: titre du flux
  • RSS_DESCRIPTION: description du flux
  • TZ_REMOTE: décalage horaire du site par rapport à UTC

Les variables commençant par $SED correspondent toutes à des listes d’expressions à passer à sed pour sélectionner un ou des éléments:

  • SED_SELECT_URL: les adresses des articles (posts)
  • SED_SELECT_ITEM: l’article avec toutes ses infos

Les expressions contenues dans les variables qui vont suivre s’appliquent à la partie de la page renvoyée par l’application de SED_SELECT_ITEM:

  • SED_ITEM_TITLE: titre de l’article
  • SED_ITEM_AUTHOR: auteur de l’article
  • SED_ITEM_DATE: date de l’article
  • SED_ITEM_CONTENT: contenu de l’article

La variable POST_ID contient quant à elle un identifiant permettant d’identifier (tiens donc…) de façon unique l’article, afin de ne pas re-télécharger sa page si on l’a déjà fait par le passé.
Il ne reste plus que la fonction pre_post() qui reçoit comme paramètre l’adresse de l’article et est exécutée avant le téléchargement de celui ci, pour le forum, on l’utilise pour définir l’id du post ainsi que l’expréssion pour le récupérer.

Récupérer le script grab.sh, et s’il est dans le même répertoire que arch.org:

./grab.sh arch.org

Si tout se passe bien, vous devriez avoir un répertoire:

/var/tmp/user_feed_cache-$USER/arch.org/

qui s’est créé avec dedans entre autre un fichier rss.xml que vous pouvez ouvrir avec votre agrégateur.

A partir de là, vous avez le choix de mettre des crontab pour mettre à jour le flux périodiquement ou si votre agrégateur le permet (liferea par exemple), renseignez lui la commande suivante:

/var/tmp/user_feed_cache-$USER/arch.org/grab.sh

( en modifiant $USER par le nom de votre utilisateur), et il s’occupera des mise à jours (ce script n’est créé que lors de la première exécution de grab.sh sans « -p »).

Par défaut, le script cherche les fichiers de configuration dans $HOME/.config/feed et dans le répertoire courant.

linuxplanet.com est un autre des sites pour lesquels j’utilise ce script dont voici le fichier de configuration: linuxplanet.
Voilà, il reste plus qu’à trouver les bonnes regexp :)

Les mises à jour magiques

Sous Archlinux, certaines mises à jour sont annonciatrices d’embouteillage sur le forum et le canal irc, mais aucune mise à jour n’est définitive et plusieurs manières existent pour revenir en arrière: Wiki downgrade, dont un projet initié par kumyo: ARM.

ARM permet de très facilement revenir dans le temps (pour peu que la journée voulue soit disponible), en théorie, il archive jusqu’à 6 mois (aujourd’hui il n’a que novembre 2009) de paquets Archlinux pour les dépôts testing, core, extra, community-testing et community, pour l’utiliser, il suffit de suivre le wiki, mais je vous propose ici un petit script qui permet d’automatiser le rollback, non pas que ça soit nécessaire mais vu le nombre d’utilisateurs sur le forum ayant des soucis avec une mise à jour, ça peut toujours servir, rollback:

#!/bin/sh
 
usage ()
{
	echo $(basename "$0")" date [pkg1 pkg2 ...]"
	exit 0
}
 
pacman_conf=$(mktemp)
pacman_mirror=$(mktemp)
verbose=0
[ -z "$1" ] && usage
rep=$(date -d "$1" +'%Y/%m/%d')
[ $? -ne 0 ] && exit 1
shift
url="http://arm.kh.nu/$rep/"
wget -q "$url" || exit 2
sed -e '/^#/d' -e "s|/etc/pacman.d/mirrorlist|$pacman_mirror|g" /etc/pacman.conf > $pacman_conf
echo Server=http://arm.kh.nu/$rep/'$repo'/os/$(arch) > $pacman_mirror
if [ -z "$1" ]; then
	pacman --config $pacman_conf -Syyuu 
else
	pacman --config $pacman_conf -Syy "$@"
fi
rm $pacman_conf
rm $pacman_mirror

Pour l’utiliser pour par exemple le 01/11/2009:

rollback 20091101 # remet le système à cette date là
rollback 20091101 xorg-server # remet le paquet xorg-server du 01/11/2009

La deuxième forme ne fonctionnera pas si les dépendances ne sont pas satisfaites.

Metacity: changer de bureau avec la molette

Le gestionnaire de fenêtre par défaut sous Gnome n’est pas parfait, mais parmi ses quelques défauts, il ne gère pas la molette de la souris pour le déplacement entre les bureaux, jusque là, je changeais tout simplement de gestionnaire en prenant Openbox qui s’intègre assez bien à gnome tout en restant très configurable, dernièrement, ayant eu un petit souci de détection du nombre de bureaux, j’ai voulu tester Metacity à nouveau… pas beaucoup de changements.

Enfin bref, tous ça pour présenter un petit programme permettant de prendre en charge la molette de la souris dont la version initiale a été postée sur un topic du forum d’Ubuntu par alduc1, ça fonctionne, mais génère une alerte de Metacity et se perd dans les bureaux si on en change depuis le pager ou avec les raccourcis clavier.

Je l’ai un peu modifié et lui ai rajouté des options, ce qui me permet de lui indiquer des fenêtres supplémentaires: sdesktop (git).
Pour utiliser le programme, on va d’abord l’installer, pour les utilisateurs d’Archlinux:

yaourt -S sdesktop

pour les autres:

wget http://tuxce.selfip.org/cgit/public/sdesktop/snapshot/sdesktop-master.tar.gz
tar zxvf sdesktop-master.tar.gz 
cd sdesktop-master
make

Libre à vous de lancer make install ou tout simplement copier l’exécutable dans votre répertoire de scripts si vous en avez un.

Une fenêtre est identifiée entre autre par une classe ou un nom, pour avoir ces éléments:

$ # lancer la commande et cliquer sur une fenêtre, conky par exemple
$ xprop WM_CLASS WM_NAME
WM_CLASS(STRING) = "Conky", "Conky"
WM_NAME(STRING) = "Conky (host)"
$ # de même pour le fond d'écran sous Gnome/Nautilus
$ xprop WM_CLASS WM_NAME
WM_CLASS(STRING) = "desktop_window", "Nautilus"
WM_NAME(STRING) = "x-nautilus-desktop"

Il ne reste plus qu’à lancer:

sdesktop desktop_window Conky

(par défaut, « sdesktop » prend la fenêtre de fond de Nautilus)

Puis tester en utilisant la molette de la souris.
Le programme se lance en tâche de fond (-f pour l’inverse), il suffit de lui envoyer un SIGKILL ou SIGTERM pour le quitter:

killall sdesktop