Skip to content

Linux Attitude

Le libre est un état d'esprit

Archive

Archive for 2014

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.

Scotch

Republié par http://lesjoiesdusysadmin.tumblr.co...

Niveau :      
Résumé : stats

Howdy ho !

Savez-vous ce qu'il y a de nouveau dans ext4 ?

Tout le monde sait à peu près qu'il y a moyen de stocker plus de fichiers et des fichiers plus gros que dans ext3. Bon c'est gentil, mais quand on ne s'appelle pas google ou la NSA, stocker des fichiers de plus de 2To n'est pas vraiment notre priorité.

De plus l'usage des extents, qui permet ce genre de choses, a l'avantage de réduire la fragmentation. Bien.

Passons à des choses plus sympathiques, savez-vous que ext4 peut stocker la liste des blocs inutilisés ? Ça n'a l'air de rien, mais du coup la durée de fsck n'est plus proportionnelle à la taille du volume, mais à la quantité de données stockées ! Enfin une bonne nouvelle.

Ext4 supporte la méthode discard, c'est à dire l'indication au block device que certains blocs ne sont plus utilisés. Cette fonctionnalité est indispensable pour conserver les performances des SSD sur le long terme.

Parlons des dates maintenant. Le format de stockage des dates a changé, ce qui veut dire deux choses : on est maintenant Y2038 safe et on peut maintenant stocker des dates précises à la nanoseconde.

De plus il est possible de stocker une date supplémentaire : la date de création (crtime). Cette information était un gros manque pour les habitués du système de Microsoft. En effet, il est trop facile et fréquent de toucher aux fichiers et par là même mettre à jour les dates du fichier. La date de création elle est immuable et permet de savoir quand est apparu un fichier.

Des nouveaux timestamps !

Ceux-ci dépendent d'une nouvelle fonctionnalité d'ext4 : les inodes de 256 octets. On ne peut donc avoir les timestamps à la nanoseconde et la date de création que sur des systèmes de fichiers fraîchement créés et pas sur des systèmes upgradés depuis ext3 s'ils avaient été créés avec la taille par défaut.

Pour pouvoir les stocker, il faut passer l'option -I 256 à la création du système de fichier.

$ mkfs.ext4 -I 256 /dev/sdXY

Et pour les utiliser ?
Sachant qu'il s'agit de fonctionnalités d'un système de fichiers, il faut passer par le VFS pour les utiliser. Le problème c'est que le VFS n'avait pas prévu ce cas. Il y a donc de nombreuses modifications à faire avant de les voir arriver dans ls : modifier le VFS pour avoir une fonction permettant de récupérer ces données, modifier l'appel système stat, modifier la libc, modifier ls et ses amis pour qu'ils affichent l'information.

C'est trop bête, nous avons l'information sur le disque et nous n'y avons pas accès. Heureusement, si on est root, un disque ça se lit, il suffit juste de savoir où est l'info et d'aller la chercher.

Lire la date de création d'un fichier

Je rappelle que les autres dates directement disponibles avec stat sont : atime (dernier accès), mtime (dernière modification du contenu) et ctime (dernière modification de métadonnées).

On récupère l'inode du fichier

$ stat -c%i fichier

On récupère la partition sur laquelle est stockée le fichier

$ df fichier | awk 'NR==1 {next} {print $1; exit}'

Et enfin on lit les infos directement sur le disque avec debugfs (il faut être root)

$ debugfs -R "stat <$inode>" /dev/sdaX

Ce qui agrégé en une ligne de commande donne pour le fichier $file :

$ file=/bin/ls; debugfs -R "stat <$(stat -c%i "$file")>" $(df "$file" | awk 'NR==1 {next} {print $1; exit}')  | grep time

Niveau :      
Résumé : hdparm -z /dev/used_device

Comment repartitionner un disque contenant une partition indispensable (par exemple /) sans rebooter ?

Si l'intégralité de votre disque est en LVM, cet article ne vous concerne pas puisque vous pouvez simplement redimensionner vos volumes LVM. Mais supposons que vous ayez au moins une "partition" que vous voulez redimensionner.

Posons une limite : il ne vous sera pas possible de toucher à une partition en cours d'utilisation et de prendre en compte cette modification sans rebooter ou la désactiver temporairement.

Une partition est dite utilisée si elle est montée ou activée en tant que swap, utilisée dans un MD lancé ou présente comme PV (physical volume) dans un VG (volume group) actif.

C'est Parti

Maintenant nous avons un disque dont une partition au moins est utilisée, et une autre (celle qu'on veut redimensionner ou déplacer) ne l'est pas.

Modifions la table des partitions avec fdisk (cfdisk ou parted feront l'affaire). Attention, pour toute autre opération qu'une création ou un changement du secteur de fin (déplacement), fdisk ne suffira pas.

Lorsque vous quittez l'outil et que vous écrivez sur le disque, celui-ci tente de relire la table des partitions. Puisqu'une des partitions est en cours d'utilisation, il vous indique qu'il n'a pas pu le faire.

Si vous pouvez libérer la partition temporairement, alors il suffit d'utiliser la commande suivante pour que sa table des partitions soit relue :

$ hdparm -z /dev/sdX

Supposons que vous ne puissiez pas libérer la partition. La solution est simplement d'utiliser un loopback ! Pour cela, récupérez l'offset à utiliser depuis la table de partition :

$ fdisk -lu /dev/sda | grep sda2
> /dev/sda2         1026048   286515199   142744576   83  Linux

Ici l'offset de début est 1026048*512 et celui de fin 286515199*512. Il n'y a plus qu'à créer le loopback. Attention pour la taille la formule est "secteur de fin - secteur de début + 1" car ces secteurs sont inclus :

# unités : octet
$ losetup -o $(($start*512)) --sizelimit $((($end-$start+1)*512)) -f --show /dev/sda 
# un message d'erreur apparait, mais il peut être ignoré

Et voilà, vous pouvez maintenant faire un resize2fs sur le device de loopback et/ou un mount directement !

PS :
On pourrait croire qu'on peut faire mieux avec device mapper et dmsetup. Mais en fait ce n'est pas possible car device mapper considère que le disque complet est en cours d'utilisation si une de ses partitions est utilisée.