Skip to content

Linux Attitude

Le libre est un état d'esprit

Archive

Tag: planete-libre

Niveau :      
Résumé : alias / /%{username}

Aujourd'hui je voudrais faire un serveur web qui se comporterait comme un serveur FTP ou SFTP. Lorsqu'un utilisateur unix se connecte à un serveur FTP avec un login et un mot de passe, il lui est présenté un contenu qui lui est propre (son $HOME par exemple).

Comment faire l'équivalent avec apache ?

Dit autrement, je voudrais que les 2 commandes suivantes renvoient un contenu différent :

$ wget http://userA@www.monserveur.com/ # répertoire A
$ wget http://userB@www.monserveur.com/ # répertoire B

Pour cela il faut jouer avec les RewriteRules, mais c'est plus balaise que ça en a l'air.

Premièrement il faut une authentification. J'ai choisi ldap, mais prenez la méthode que vous préférez : http://httpd.apache.org/docs/2.2/mo... tout ce qui commence par mod_authn est valable. Voici comment on la met en place :

<Location />
        AuthType basic
        AuthName "My server"
        AuthBasicProvider ldap
        AuthLDAPURL ldap://serveur.ldap.com/dc=domaine,dc=com?uid?sub
        AuthLDAPBindDN cn=user,ou=technical,dc=domaine,dc=com
        AuthLDAPBindPassword password
        Require valid-user
</Location>

Ensuite on joue avec RewriteRule, les variables s'appellent sous la forme %{ENV:VARIABLE}

# utilisez %{ENV:USER_AUTH} pour ceux qui n'ont pas choisi l'authent LDAP
RewriteRule ^(.*) /%{ENV:AUTHENTICATE_uid}/$1

Mais ça ne marche pas. Tout d'abord on apprend qu'il faut mettre les règles dans le Location sinon les variables d'authentification ne sont pas disponibles. Ensuite on a oublié d'activer le rewrite engine. Et enfin dans un location (ou un directory) on ne matche plus la request uri mais le chemin créé à partir de cette uri. Cela qui une fois corrigé nous donne quelque chose comme ça :

<Location />
        RewriteEngine On
        # le résultat sera automatiquement préfixé par le DocumentRoot si on ne le fait pas nous même
        # notez l'absence du / initial dans le pattern ...
        RewriteRule ^var/www/html/(.*) /%{ENV:AUTHENTICATE_uid}/$1 
</Location>

Mais ça ne marche toujours pas. En effet, le rewrite engine d'apache est réentrant, quelle que soit la modification et quel que soit le flag utilisé, si une url est modifiée, apache fait une redirection interne et relance toute la machinerie (dont les redirections). Pour les petits malins, non [L] n'est pas fait pour ça, par contre la doc évoque un [END] qui aurait cette fonctionnalité mais je ne l'ai pas trouvé.

Il nous faut donc un moyen de détecter qu'une url a déjà été transformée par une RewriteRule. Malheureusement les variables (comme %{ENV:AUTHENTICATE_uid}) ne sont valables que dans la partie gauche de RewriteCond ou dans la partie droite de RewriteRule ce qui nous limite sévèrement. On ne peut pas matcher le chemin en pour détecter qu'il contient le répertoire de l'utilisateur. De plus on ne peut pas utiliser une autre racine, apache ajouterait automatiquement le DocumentRoot en cours.

J'ai essayé en utilisant des variables d'environnement temporaire (avec [E=VAR:VALUE]), mais le rewrite engine l'évalue trop tard et ne détecte pas la nouvelle valeur de la variable modifiée par lui-même.

Ma solution est donc de mettre en place un unique répertoire contenant les utilisateurs avec un nom improbable car il ne pourra pas être utilisé comme nom de répertoire dans les répertoires utilisateurs. Et d'utiliser ce nom de répertoire comme marqueur d'url déjà traitée. Ce qui nous donne :

        # mon répertoire s'appelle ____data____
        RewriteRule ^var/www/html/(?!____data____/)(.*) /____data____/%{ENV:AUTHENTICATE_uid}/$1

C'est bien joli, mais ça n'empercherait pas un utilisateur d'aller voir dans le répertorie de son voisin. En effet, ce ne sont que des rewrite rules, pas des droits d'accès. Puisqu'on ne peut pas utiliser les noms de répertoire utilisateur dans les require pour le matcher avec les nom d'utilisateur (on se mordrait la queue (et ça fait mal (au dos))). Il nous faut donc le garantir d'une autre façon, en forçant tout utilisateur a n'accéder qu'à son répertoire avec une autre règle.

        # ce qu'on veut c'est éviter l'utilisateur qui voudrait bypasser la première règle avec un http://www.monserveur.com/____data____/userX
        RewriteRule ^var/www/html/____data____/.*?/(.*) /var/www/html/____data____/%{ENV:AUTHENTICATE_uid}/$1
        # et on voudrait ausst éviter que l'utilisateur puisse scanner la racine
        RewriteRule ^var/www/html/____data____/?$ /var/www/html/____data____/%{ENV:AUTHENTICATE_uid}/

Notez l'ajout de /var/www/html dans les chaines de remplacement, c'est pour éviter qu'apache pense qu'on a modifié le chemin si on n'a rien changé.

Et c'est gagné, on a enfin trouvé !

Je vous laisse donc profiter du résultat :
Edit : la version finale minimise l'appel aux règles, prend en compte les chemins qui se terminent par / et les tentatives d'accès à des répertoires non autorisés.

<Location />
        AuthType basic
        AuthName "My server"
        AuthBasicProvider ldap
        AuthLDAPURL ldap://serveur.ldap.com/dc=domaine,dc=com?uid?sub
        AuthLDAPBindDN cn=user,ou=technical,dc=domaine,dc=com
        AuthLDAPBindPassword password
        Require valid-user

        # make http behave like ftp
        RewriteEngine On
        # create home dir var
        RewriteRule .* - [E=USER_ROOT:/var/www/html/____data____/%{ENV:AUTHENTICATE_homeDirectory}]
        RewriteCond %{ENV:USER_ROOT} !-d
        RewriteRule .* - [E=USER_ROOT:/var/www/html/forbidden]

        # redirection vers les repertpoires utilisateur
        RewriteCond %{REQUEST_FILENAME} !^/var/www/html/____data____
        RewriteRule ^var/www/html/(.*) %{ENV:USER_ROOT}/$1 [L,DPI]

        # impossibilite de lire la racine
        RewriteCond %{REQUEST_FILENAME} ^/var/www/html/____data____/?$
        RewriteRule .* %{ENV:USER_ROOT} [L,DPI]

        # impossibilite de lire le repertoire d'un autre
        RewriteCond %{ENV:AUTHENTICATE_homeDirectory}|%{REQUEST_FILENAME} !^(.*?)\|/var/www/html/____data____/\1
        RewriteRule ^var/www/html/____data____/?[^/]*/?(.*) %{ENV:USER_ROOT}/$1 [L,DPI]
</Location>

<Directory /var/www/html/forbidden>
        deny from all
</Directory>

Note : et pour ceux qui voudraient vraiment faire du FTP avec apache il y a mod_ftp.

... désolé

Niveau :      

Résumé : gdisk /dev/sda

Le format GPT

Guid partition table est un format de partitionnement de disque.

Il ne faut pas confondre un format de partitionnement avec le formatage d'une partition avec système de fichier. Il y a de nombreux formats de système de fichier : ext4, swap, xfs ... Mais il n'existe que peu de format de partitionnement, les plus connus étant :

  • MBR : format utilisé par les premiers PC sous DOS et encore en usage sur la beaucoup de vos machines
  • disklabel : utilisé sur solaris et BSD
  • GPT : apparu récemment (il y a environ 15 ans) pour les besoins de l'itanium

Ce format a pour but de palier les différents problèmes de son prédécesseur direct le MBR :

  • stockage de la table en double et checksum du contenu : la table étant une structure très importante, on peut enfin se dire qu'on ne la perdra plus
  • stockage des offset en LBA sur 64 bits : on arrête de parler de CHS obsolètes depuis longtemps et on espère pouvoir tenir assez longtemps la croissance des tailles de disques : 9 milliards de téra octets avec des secteurs de 512 octets
  • on dépasse donc la limite des 2To supportés par le format MBR, si vous avez un disque de plus de 2Tio il est a peu près certain qu'il a déjà du GPT
  • tous les identifiants sont des UUID : garantis uniques, on peut en créer autant qu'on veut (2^128) et il y en a partout
  • la table fait au minimum 16kio : on n'a plus de question de table primaire/logique/étendue et on peut stocker au moins 128 partitions sans se poser de question
  • accessoirement on peut stocker des noms de partition directement dans la table

Attention, on stocke des adresses de secteur (LBA comme en MBR depuis un certain temps) et non d'octets, et la taille d'un secteur peut varier d'un disque à l'autre, il faut faire attention à ne pas copier les tables GPT trop littéralement.

GPT est indiqué comme nécessaire pour le support du boot sur EFI, bien qu'il soit théoriquement possible de faire sans.

Partitionner en GPT

Pour partitionner en GPT vous avez le choix entre deux familles d'outil :

  • parted et gparted
  • gdisk, sgdisk et cgdisk (remplaçants de la famille fdisk)

Le moins dangereux est de ne partitionner que vos nouveaux disques en GPT, mais il y a moyen de refaire la table de partition d'anciens disques s'il y a suffisament de place pour stocker la table GPT (16kio en début et en fin de disque plus le MBR). Si l'espace est disponible, c'est simple, il vous suffit de reporter les adresses de début et de fin de chaque partition du MBR vers le GPT.

Choix des partitions

Tout d'abord je vous recommande d'aligner vos partition sur 1Mio, le minimum recommandé étant de 4kio. Le minimum de 4ko s'explique par le fait que de plus en plus de disques ont des secteurs de 4ko, et si vos écritures ne sont pas alignées sur 4kio vous allez voir vos performances dégringoler.

Il faut ajouter que de plus en plus de disques sont des SSD. Les SSD ont des pages sur lesquelles il est aussi intéressant de se caler et elles peuvent aller jusqu'à 1Mio.

Donc ne vous posez plus la question et prenez la valeur par défaut de l'outil qui aligne sur le Mio.

  1. Si vous avez un boot sur EFI, vous devez faire une partition EFI (type ESP), ne soyez pas radin, mettez-y au moins 100Mo
  2. Si vous avez un boot sur un BIOS d'origine, il est conseillé de faire une partition de type bios. Certaines personnes indiquent que celle-ci est indispensable car GPT ne laisse pas de place caché pour le bootloader. C'est faux puisqu'il suffit d'aligner les partitions pour faire apparaître de la place. Mais puisqu'on en en est à faire des trucs propres, profitez-en pour faire ce qui aurait du être fait depuis très longtemps et faites de la place pour stocker un bon grub2 avec tous ses modules (1Mo)
  3. Si vous voulez permettre l'hibernation de votre machine (ou si vous avez peu de ram) n'oubliez pas d'inclure une partition de swap.
  4. Pensez à séparer système et données sur deux partitions différentes. La partition de données est naturellement /home pour une particulier, mais sur un serveur c'est plus flou : /var /srv /home sont des répertoire de données.

Compatibilité MBR

Dans la notion de MBR (un unique secteur de 512 octets) il faut différencier le code et la table des partitions.

Si vous utilisez un BIOS classique, le code du MBR restera le même (grub/lilo/boot windows ...).

Si vous utilisez EFI, le code du MBR peut être vide (ce que fait en général gdisk), mais il peut être intéressant de mettre un code fonctionnel avec un avertissement.

La table des partitions du MBR doit elle être protégée pour éviter à un outil d'édition de cette table de tenter d'y faire des modifications et d'effacer vos précieuses données. C'est pour cela qu'on y inscrit un "protective MBR" qui indique que le disque est entièrement utilisé par une partition unique de type GPT.

Niveau :      
Résumé : ip link add link eth0 vlan1 type vlan id 1

Je suis de retour !

Désolé pour le lag ... mais je réponds aux commentaires.

Problème

Aujourd'hui, un problème qu'on m'a posé récemment. Comment faire lorsqu'on a un parc de box (routeur wifi, machine embarquée, ...) et qu'on veut pouvoir à tout moment se connecter physiquement sur son port ethernet et la configurer en utilisant ip (par ssh, snmp ...).

La première solution est d'avoir une configuration réseau immuable sur ces machines ET de répertorier d'une façon ou d'une autre un identifiant unique pour chacune de ces machines qu'on peut alors faire correspondre à une ip. C'est assez contraignant et ça impacte fortement la configuration réseau des machines. Ça risque de nous empêcher de réutiliser ce port pour communiquer dans un réseau existant le reste du temps.

La deuxième solution serait d'utiliser un protocole type zeroconf pour configurer automatiquement le réseau lorsqu'on se branche, l'inconvénient est de réussir à le désactiver lorsque la machine se retrouve dans son réseau de destination qui n'utilise pas nécessairement zeroconf tout en le gardant actif pour le configurateur.

Je vous propose donc une solution différente : l'ip unique. Toutes les machines à configurer ont la même IP. C'est bien beau me direz-vous, mais comment fait-on pour éviter les conflits sur le réseau de destination ? Et comment fait-on pour que ces machines communiquent ensemble ?

C'est tout simple, on met cette IP sur un vlan prédéfini. Ainsi vous n'avez plus aucune contrainte sur la configuration réseau de l'appareil. Ce peut être une box en bridge ou en routeur, une machine physique avec un routage complexe, ou une machine configurée en dhcp.

Solution pour linux

Pour ajouter une interface réseau virtuelle associée à un vlan :

# le vlan 1 sur l'interface eth0 sera dans l'interface virtuelle vlan1 
$ ip link add link eth0 vlan1 type vlan id 1 

# ou, pour ceux qui n'aiment pas le couteau suisse, ip, il y a l'outil d'origine
$ vconfig add eth0 1 # pas le choix, l'interface s'appellera nécessairement eth0.1

Et il suffit de lui configurer une ip choisie en dur et c'est fini, vous pouvez mettre n'importe quelle configuration pour eth0 ...

$ ip addr add 192.168.254.254/28 dev eth0.1

Pour faire ceci en statique, sur une debian like il faut modifier /etc/network/interfaces en nommant l'interface à configurer eth0.1 Pour les redhat like il faut créer le fichier /etc/sysconfig/network-script/ifcfg-eth0.1

Niveau :      
Résumé : ntp.conf ; fudge

Pour vérifier le bon fonctionnement de votre démon ntp, vous êtes amené à taper la commande suivante qui liste les source de temps utilisées :

$ ntpdc -p

Cette commande met une étoile face à la source de référence utilisée pour la synchronisation. Le choix se fait entre autre en fonction du stratum de la source. Je rappelle que les serveurs NTP disposant d'une source de temps matérielle fiable (horloge atomique) ont pour stratum 1. Ceux qui se synchronisent sur eux, 2, et ainsi de suite.

Étant donné qu'il y a un grand nombre de serveurs publics de strate 2 et 3, vous devriez avoir accès à des serveurs de strate 4, ou au pire 5. Mais si le serveur a une strate plus élevée, il se peut que l'horloge choisie ne soit plus le serveur, mais l'horloge locale qui a une strate définie par défaut à 5 sur certaine distributions.

Et là c'est le drame, vous n'êtes plus synchronisés !

Pour résoudre ce problème, il y a plusieurs méthodes, se résumant toutes en la configuration des serveurs de temps :

# ntp.conf

# mettre l'option prefer sur le serveur voulu
serveur xxx.com prefer
# réduire la strate du serveur
fudge xxx.com stratum 4

# augmenter la strate de l'horloge locale
# 127.127 pour les horloges non réseau
# 1.0 pour l'horloge système
fudge 127.127.1.0 stratum 10

Niveau :      
Résumé : vlock; vlock -ns

Vous avez vu apparaître dans l'article sur tmux, un petit outil pour verrouiller le terminal, il s'appelle vlock.

Son unique fonctionnalité est le locker un terminal et de demander un mot de passe pour être débloqué.

Mine de rien ça lui fait quand même deux cas d'usage :

  • bloquer l'accès physique à une machine
  • bloquer l'accès virtuel à un shell

Virtuel

Avec la commande suivante :

$ vlock

Vous bloquez votre terminal en cours, et seul un mot de passe peut le débloquer. C'est utile essentiellement lorsque vous êtes connecté en ssh à distance sur une machine.

Physique

L'option -a permet de locker toutes les consoles locales (ctrl-alt-Fx, ou alt-Fx), en pratique il locke la console en cours et empêche d'en changer. Il faut donc déjà être sur une console locale.

Si vous êtes sur X, vous êtes aussi sur une console locale (remarquez le ctrl-F7 pour y aller). Mais le shell qui va lancer votre commande ne l'est pas, il est dans le terminal virtuel de xterm, rxvt, konsole et consorts. Pour locker toutes les consoles, il faut donc utiliser l'option -n qui ouvre une nouvelle console (avec openvt) avant de continuer avec l'option -a.

Enfin notez que l'utilisateur local a en général accès aux magic keys, et une de ces magic keys sert justement à tuer le processus en avant plan (alt-sysrq-k), par exemple pour garantir qu'il n'y a pas de keylogger. Si vous ne voulez pas vous faire tuer votre session par cette combinaison de touche vous pouvez utiliser l'option -s. C'est là qu'on voit que cette combinaison nommé SAK n'est pas si sécurisée que ça puisqu'elle peut être désactivée...

Donc je résume :

# en tant qu'utilisateur normal et seulement depuis une console texte
$ vlock -a
# en tant que root
$ vlock -sn

Quand le lancer

Et c'est là qu'est la difficulté, en toute logique le lancement doit se faire par le processus qui dispose du terminal à un instant donné, surtout dans le cas de blocage du terminal virtuel. La bonne solution est de le lancer après un certain temps d'inactivité, et seule l'application peut savoir quand le lancer. C'est donc à vous de trouver les settings spécifiques à l'application pour le faire.

Mon article précédent indique comment faire pour tmux, malheureusement je n'ai pas trouvé de solution pour bash qui ne propose que la variable TMOUT qui termine complètement le shell.

Niveau :      
Résumé : tmux

Comme disait un illustre au grand cœur, "Compromis, chose due !" (orthographe approximative). Voici donc mon fichier de configuration détaillé de tmux, à mettre dans ~/.tmux.conf ou /etc/tmux.conf au choix. Je n'ai pas changé beaucoup de raccourcis car je tiens à m'habituer autant que possible aux valeurs par défaut qui vont se retrouver sur mes nouveaux serveurs.

J'en profite pour ajouter un raccourci que j'ai oublié la dernière fois :

  • ctrl-b D : pour détacher un tmux resté ouvert à distance
# Pour les nostalgiques de screen
# comme les raccourcis ne sont pas les mêmes, j'évite
#set -g prefix C-a
#unbind-key C-b
#bind-key a send-prefix

# même hack que sur screen lorsqu'on veut profiter du scroll du terminal (xterm ...)
set -g terminal-overrides 'xterm*:smcup@:rmcup@'

# c'est un minimum (defaut 2000)
set-option -g history-limit 100000

# lorsque j'ai encore un tmux ailleurs seule
# sa fenetre active réduit la taille de ma fenetre locale
setw -g aggressive-resize on

# locker la session après inactivité (en s)
set -g lock-after-time 3600
# pour que le lock marche sous linux (apt-get install vlock)
set -g lock-command vlock

# il faut choisir un derivé de screen, 256 couleurs c'est bien !
set -g default-terminal "screen-256color"

# pour ceux qui n'ont pas laché la souris
set -g mouse-select-pane on
setw -g mode-mouse on

# ca peut etre utile ...
set -g status-utf8 on
setw -g utf8 on

# Pour etre alerté sur un changement dans une autre fenêtre
setw -g monitor-activity on
#set -g visual-activity on
#set -g visual-bell on

# numéroter a partir de 1, pratique pour l'accès direct
set -g base-index 1

# repercuter le contenu de la fenetre dans la barre de titre
# reference des string : man tmux (status-left)
set -g set-titles on
set -g set-titles-string '#H #W #T' # host window command


#########
# theme #
#########
# exprimez votre créativité ici !
# pour les string : man tmux (status-left)

# barre un peu plus discrete
set -g status-bg default
set -g status-fg green
setw -g window-status-current-bg default
setw -g window-status-current-fg white
setw -g window-status-alert-attr default
setw -g window-status-alert-fg yellow

set -g pane-active-border-fg green
set -g pane-active-border-bg black
set -g pane-border-fg white
set -g pane-border-bg black

set -g message-fg black
set -g message-bg green

# exemples de barre d'état 
#set -g status-left '#[fg=red]#H#[fg=green]:#[fg=white]#S #[fg=green]][#[default]'
#set -g status-right '#[fg=green]][#[fg=white] #T #[fg=green]][ #[fg=blue]%Y-%m-%d #[fg=white]%H:%M#[default]'

#set -g status-left '#[fg=red]#H#[fg=green]:#[fg=white]#S #[fg=green]][#[default]'
#set -g status-right '#[fg=green]][ #[fg=blue]%Y-%m-%d #[fg=white]%H:%M#[default]'

#set -g status-left '#[fg=green](#S) #(whoami)@#H#[default]'
#set -g status-right '#[fg=yellow]#(cut -d " " -f 1-3 /proc/loadavg)#[default] #[fg=blue]%H:%M#[default]'

#set -g status-right "#[fg=yellow]#(uptime | cut -d ',' -f 2-)"

Comme pour le bashrc collaboratif, je vous propose de poster en commentaires vos personnalisations, je les ajouterai.

Niveau :      
Résumé : tcpdump ssl ; ptrace ; ltrace

Vous attendez la suite de mon article sur ce qui passe par les oreilles d'un android ? Hé bien vous allez attendre encore un peu ...

Lorsque vous récupérez via tcpdump un flux SSL (au hasard du https), il est chiffré et c'est justement l'intérêt du SSL de vous empêcher de lire ce flux.

Mais si si vous maitrisez une des deux extrémités, il devrait être normal que vous puissiez lire ce flux. C'est pourquoi nous allons le faire.

Côté serveur

Dans le cas où vous maitrisez le côté serveur, il suffit d'ouvrir la trace tcpdump (sauvegardée avec l'option -s0 -w file) sous wireshark et de le configurer pour qu'il utilise la clé serveur pour déchiffrer le flux :comme ici et de choisir de suivre le flux ssl au lieu du flux TCP.

C'est simple et efficace.

Côté client

Maintenant si vous êtes côté client sans certificat client, vous êtes coincés. Et c'est là que j'ai une solution à vous proposer.

Il existe plusieurs moyen pour espionner vos processus, tout d'abord vous pouvez créer un wrapper autour de la lib SSL et utiliser LD_PRELOAD pour la charger avant le processus. C'est bien mais difficile à mettre en œuvre, surtout si le processus tourne déjà, je vous laisse explorer cette voie de votre côté.

La deuxième solution est d'utiliser ptrace pour espionner le processus. Techniquement complexe, cette méthode nous est grandement facilitée par l'outil ltrace.

Pour la suite je vais supposer que les services à espionner passent par openssl, mais rien ne vous empêche de faire la même chose avec gnutls.

Espionner un processus

C'est simple :

# vous le lancez directement : 
$  ltrace ma commande
# ou vous espionnez un processus qui tourne déjà 
$ ltrace -p pid

Ça vous montre le fonctionnement, mais c'est aussi illisible qu'un strace.

Espionner le SSL

Ajoutons quelques options pour trier ce fouillis :

$ ltrace -l /usr/lib/libssl.so.0.9.8 -s 20000 -e SSL_read,SSL_write

Et voilà, la liste des appels ! Mais ce n'est pas suffisant.

Ajoutons les lignes suivantes dans /etc/ltrace.conf (ou dans ~/.ltrace.conf) :

int SSL_read(addr,string[retval],int);
int SSL_write(addr,string[arg3],int);

On relance la commande et maintenant nous avons le contenu de la communication en clair.

Mais il y a un petit bug dans ltrace, string[retval] devrait couper les chaines de SSL_read en fonction de la valeur de retour, mails ne le fait pas.

Corrigeons cela avec un petit script de formatage et cette fois nous avons toute la communication en clair !

$ ltrace -l /usr/lib/libssl.so.0.9.8 -s 20000 -e SSL_read,SSL_write -p pid 2> /tmp/trace
$ perl -pe 's/(SSL_read.*?, ")(.*)(".*? )(\d+)$/$1.substr($2,0,$4).$3.$4/e' /tmp/trace | less