Apache : « AH01797: client denied by server configuration » sur le dossier icons

Un client m’a remonté que sur son site le favicon était en erreur 404, de façon incompréhensible.

Si j’essaye d’accéder au favicon avec mon navigateur, j’ai bien une erreur 404. Et dans les logs je vois :

[Fri Feb 26 11:38:36.170743 2021] [access_compat:error] [pid 11523:tid 139967505688320] [client XXX.XXX.XXX.XXX:0] AH01797: client denied by server configuration: [...]/current/favicon.ico

Pourtant le fichier favicon.ico est bien présent au bon emplacement et avec les bons droits.

 

J’ai dû pas mal chercher pour trouver la source du problème. C’est ce site qui m’a aidé.

En fait, le module alias contiens par défaut la configuration suivante :

        # We include the /icons/ alias for FancyIndexed directory listings.  If
        # you do not use FancyIndexing, you may comment this out.

        Alias /icons/ "/usr/share/apache2/icons/"

        <Directory "/usr/share/apache2/icons">
                Options FollowSymlinks
                AllowOverride None
                Require all granted
        </Directory>

Sur tous les vhosts du serveur, le dossier /icons/ est réécrit vers /usr/share/apache2/icons/, donc toutes les icônes ajoutées par le client ne sont pas accessibles.

La solution évoquée sur le site est de renommer le dossier /icons/ sur le site. Ça ne me conviens pas, parce-qu’il faut que le client modifie son site. La seule solution est de commenter ces lignes.

Drupal et PostgreSQL : Error at offset 0 of … bytes drupal/includes/cache.inc

Il y a quelques jours j’ai dû copier un site Drupal de prod vers un autre serveur, pour en faire une préprod. Malgré une configuration qui semblait entièrement ISO, j’avais une plâtrée de messages d’erreur, du type :

Notice: unserialize(): Error at offset 0 of 1009 bytes in [...]drupal/includes/cache.inc on line 449
Notice: unserialize(): Error at offset 0 of 50487 bytes in [...]drupal/includes/cache.inc on line 449
Warning: Invalid argument supplied for foreach() in [...]drupal/includes/module.inc on line 213
Warning: array_keys() expects parameter 1 to be array, null given in [...]drupal/includes/module.inc on line 89
Notice: unserialize(): Error at offset 0 of 50487 bytes in [...]drupal/includes/cache.inc on line 449
Warning: Invalid argument supplied for foreach() in [...]drupal/includes/module.inc on line 213
Warning: array_keys() expects parameter 1 to be array, null given in [...]drupal/includes/module.inc on line 89
Notice: unserialize(): Error at offset 0 of 1009 bytes in [...]drupal/includes/cache.inc on line 449
Notice: unserialize(): Error at offset 0 of 13 bytes in [...]drupal/includes/cache.inc on line 449
Notice: unserialize(): Error at offset 0 of 50487 bytes in [...]drupal/includes/cache.inc on line 449
Warning: Invalid argument supplied for foreach() in [...]drupal/includes/module.inc on line 213
Warning: array_keys() expects parameter 1 to be array, null given in [...]drupal/includes/module.inc on line 89
Notice: unserialize(): Error at offset 0 of 50487 bytes in [...]drupal/includes/cache.inc on line 449
Warning: Invalid argument supplied for foreach() in [...]drupal/includes/module.inc on line 213
Warning: array_keys() expects parameter 1 to be array, null given in [...]drupal/includes/module.inc on line 89
Notice: unserialize(): Error at offset 0 of 50487 bytes in [...]drupal/includes/cache.inc on line 449
Warning: Invalid argument supplied for foreach() in [...]drupal/includes/module.inc on line 213
Warning: array_keys() expects parameter 1 to be array, null given in [...]drupal/includes/module.inc on line 89
Fatal error: Call to undefined function system_run_automated_cron() in [...]drupal/includes/common.inc on line 2784
Il m’a fallu du temps pour trouver comment corriger ce problème. (d’ailleurs c’est même pas moi qui ai trouvé)
D’après internet, ces messages indiquent un problème dans la sérialisation des données.
Drupal a une drôle de façon de stocker ses données. Par exemple, si sur le serveur de base de données de prod je fais un :

SELECT variables FROM watchdog WHERE wid=10969;

ça me retournes :

a:2:{​​​​​​​s:5:"@type";s:4:"page";s:6:"%title";s:52:"Titre chelou, j'ai pas le droit de mettre le vrai";}

Je ne sais pas pourquoi ils ont fait ça, mais Drupal utilise une base de données PostgreSQL pour ensuite stocker des données formatées en JSON.
Maintenant, si je fais la même requête sur le serveur de base de données de préprod, j’ai :

\x5469747265206368656C6F752C206A27616920706173206C652064726F6974206465206D6574747265206C652076726169

Le résultat est retourné au format hexadécimal. Si on le convertit en texte, on obtient bien la même chaîne que sur le serveur de prod. C’est juste le format de la donnée qui est différente.
En fait le serveur de base de données de prod avait été installé avec PostgreSQL 8, puis a ensuite été mis à jour vers PostgreSQL 9. Le serveur de prérpod, plus récent, a été installé directement en version 9.
Sauf qu’entre les versions 8 et 9 de PostgreSQL, la gestion par défaut des données a changé
Ce qui me pose problème dans ce cas précis, c’est le bytea_output, qui est à escape en prod, mais à hex en préprod. Ca se corrige très simplement avec :

ALTER DATABASE nom_de_la_base SET bytea_output to 'escape';

Apache : AH01071: Got error Primary script unknown

Lors de la création d’un vhost sur Apache, une fois le code du site importé j’ai eu l’erreur suivante dans les logs :
AH01071: Got error 'Primary script unknown\n'
Plusieurs pages du site affichaient également un File not found.

 

J’ai pas mal galéré avant de trouver l’origine du problème, et surtout comment le résoudre.

 

Le code PHP du client était exécuté via FPM, avec la directive suivante :
ProxyPassMatch ^/(.*\.php)$ fcgi://127.0.0.1:9000/var/www/palc.fr/$1

Mais à la racine de son site, un fichier .htaccess était rempli de règles de ce style :
RewriteRule ^/gallery/index.php /phototheque.php [NC,L]
RewriteRule ^/gallery/client.php /phototheque-client.php [NC,L]

Le problème c’est que le ProxyPassMatch est exécuté avant les RewriteRule du .htaccess. Du coup, quand on demande une page PHP correspondant à une RewriteRule, Apache va d’abord essayer de l’exécuter avec FPM et retourner une erreur, puisque le fichier PHP n’existe pas.

 

La solution est de demander à Apache de n’utiliser FPM que si le fichier existe. Il faut remplacer
ProxyPassMatch ^/(.*\.php)$ fcgi://127.0.0.1:9000/var/www/palc.fr/$1
Par :
<FilesMatch \.php$>
SetHandler "proxy:fcgi://127.0.0.1:9000/"
</FilesMatch>

Magento : ajouter un administrateur avec MySQL

Je me suis retrouvé récemment à devoir me connecter à la console d’admin d’un Magento 1, dont je ne connaissait aucun identifiant. J’avais tout juste accès à MySQL. Sur internet, la plupart des articles proposent de passer par bin/magento, qui n’était pas utilisable dans mon cas. Mais j’ai finalement trouvé la solution chez Webnoo :

LOCK TABLES `admin_role` WRITE , `admin_user` WRITE;

SET @SALT = "ls";
SET @PASS = CONCAT(MD5(CONCAT( @SALT , "adminpassword") ), CONCAT(":", @SALT ));
SELECT @EXTRA := MAX(extra) FROM admin_user WHERE extra IS NOT NULL;

INSERT INTO `admin_user` (firstname,lastname,email,username,password,created,lognum,reload_acl_flag,is_active,extra,rp_token_created_at) VALUES ('AdminFirstname','AdminLastname','admin@email.com','adminusername',@PASS,NOW(),0,0,1,@EXTRA,NOW());
INSERT INTO `admin_role` (parent_id,tree_level,sort_order,role_type,user_id,role_name) VALUES (1,2,0,'U',(SELECT user_id FROM admin_user WHERE username = 'adminusername'),'AdminFirstname');

UNLOCK TABLES;

 

De l’aléatoire prévisible

J’ai voulu créer un nouveau bucket sur AWS. Comme souvent, je mets un nom aléatoire. Mais aujourd’hui j’ai eu une surprise :

Comment un bucket avec un tel nom peut déjà exister ?

La réponse est simple. Pour générer le nom aléatoire, je fais un md5sum sur la sortie de pwgen :

pwgen | md5sum
d605a2ab78b9c7ccae50828133ffa30c  -

Sauf qu’aujourd’hui, j’ai fait :

pwger | md5sum 
bash: pwger: command not found
d41d8cd98f00b204e9800998ecf8427e

Notez le pwger à la place du pwgen.

Le command not found est envoyé sur STDERR, donc n’est pas pris en compte par md5sum. Du coup le md5sum est fait sur rien. D’ailleurs on peut arriver au même résultat avec :

echo -n '' | md5sum
d41d8cd98f00b204e9800998ecf8427e  -

Note : le -n sert à éviter le retour chariot.

Si le bucket existait déjà, c’est juste parce-que je ne suis pas être le seul boulet à faire des fautes de frappe.

Comment ne pas anonymiser des données

Il y a quelques jours je suis tombé par hasard sur cet article du Parisien : Essonne : des centaines d’amendes pour non-respect du confinement établies sans contrôles ?

Le contenu de l’article ne m’intéresse pas plus que ça ici. Mais au tiers de l’article on peut voire cette image :

Il s’agit d’une personne anonyme nous montrant une contravention pour « Déplacement hors du domicile interdit », ainsi que sont attestation de déplacement sur son téléphone.

Son nom et son adresse ont été masqués sur la contravention. Par contre le QR Code de l’attestation est bien visible. Et une fois décodé et mis en forme, il donne beaucoup d’informations :

Créé le : 16/04/2020 à 19h35
Nom : Assam
Prénom : Mohamed
Naissance : 31/08/1995 à Ivry sur Seine
Adresse : 1 rue du 19 mars 1962 91860 Epinay-sous-Sénart
Sortie : 16/04/2020 à 19h35
Motifs : courses

Note : dans cet article j’ai recopié les informations sans les censurer. Elles sont déjà sur le site du Parisien, qui a nettement plus d’audience que le mien. J’ai également écrit au Parisien pour les prévenir, mais ils ne m’ont pas répondu.

Vérifier un tweet

Aujourd’hui je suis tombé sur cet échange de tweets :

D’après @PerdereauxP, beaucoup de riches le sont devenu grâce à leur travail. Ce n’est pas compliqué à vérifier, même si c’est un peu chiant. J’ai donc pris les 25 personnes les plus riches de France d’après le classement de challenges.fr. Voilà ce que ça donne :

Classement Nom Fortune (M€) Héritier
1 Bernard Arnault et sa famille 88286 Oui
2 Alain Wertheimer et Gérard Wertheimer ainsi que leur famille 50000 Oui
3 Françoise Bettencourt-Meyers et sa famille 45800 Oui
4 Famille Hermès 43000 Oui
5 Gérard Mulliez et sa famille 32000 Oui
6 François Pinault et sa famille 29000 Non
7 Laurent, Olivier, Marie-Hélène & Thierry Dassault 23000 Oui
8 Pierre Castel et sa famille 14000 Non
9 Emmanuel Besnier et sa famille 12000 Oui
10 Patrick Drahi 9000 Non
11 François Perrodo et sa famille 8500 Oui
12 Vincent Bolloré 7300 Oui
13 Pierre Omidyar 7300 Non
14 Pierre Bellon et ses enfants 6500 Oui
14 Danièle Ricard et sa famille 6500 Oui
16 Xavier Niel et sa famille 5900 Non
17 Famille Courtin-Clarins 5800 Oui
18 Rodolphe Saadé et sa famille 5500 Oui
19 Anne Beaufour et Henri Beaufour ainsi que leur famille 5300 Oui
20 Margarita Louis-Dreyfus et sa famille 5200 Oui
20 Alain Mérieux et sa famille 5200 Oui
22 Benjamin de Rothschild et sa famille 5000 Oui
23 Marie-Christine Coisne-Roquette et Familles Coisne et Lambert 4800 Oui
24 Famille Decaux 4400 Non
25 Marc Ladreit de Lacharrière 4300 Oui

Si je fais le total de tout ça j’arrive à :

Fortune total (M€) Pourcentage
Héritier 433586 95%
Pas héritier 23000 5%

@PerdereauxP a une drôle de définition de « s’en donner les moyens » et de « durement travailler ».

MySQL : Copie une base de données d’un serveur à un autre

Une petite commande pense-bête, qui permets de copier une base de données MySQL d’un serveur à un autre. Quand on est sur le serveur de destination :

ssh SERVER_SOURCE 'mysqldump base_de_donnees_source | gzip' | gunzip | mysql base_de_donnees_cible

Les gzip / gunzip sont facultatifs. Ils permettent de compresser les données pendant le transfert pour gagner du temps. Mais si SERVER_SOURCE est particulièrement lent, ça peut être plus rapide de les enlever.

Debian : Troller le RSSI avec Trolldeb

Dans le cadre de mon travail j’ai accès à des données sensibles. Il arrive que le RSSI (Responsable de la Sécurité des Systèmes d’Information) fasse un export de tous les paquets installé sur les postes Linux pour vérifier que rien ne compromets la sécurité. Il est possible de s’amuser un peu avec ça.

Comme mon ordinateur est sous Debian, je vais créer mon propre paquet Debian avec un nom qui devrait faire bondir le RSSI.

Le paquet va s’appeler troll.deb. Je créé d’abord son arborescence du projet :

mkdir -p trolldeb/DEBIAN

Ensuite je créé le fichier trolldeb/DEBIAN/control, qui contient toutes les métadonnées du paquet. Son contenu est :

Package: bitcoin-bittorent-counterstrike-dota-crack-diablo-fortnite-hack-keygen-keylogger-leagoflegend-lol-megaupload-monero-nocd-nordvpn-piratebay-popcorntime-starcraft-steam-tartiflette-tor-youporn
Version: 0.0
Priority: optional
Architecture: all
Maintainer: PALC <contact@palc.fr>
Description: Salut Sébastien, comment ça va ?

J’ai mis le minimum vital pour que ça compile sans erreur. La variable Package correspond au nom qu’aura le paquet une fois installé. À ce niveau je me suis lâché. La variable Description apparaît à côté du nom du paquet quand on les listes. (question bonus : devinez comment s’appelle le RSSI)

Il ne reste plus qu’à créer le paquet :

$ dpkg-deb --build trolldeb
dpkg-deb: building package 'bitcoin-bittorent-counterstrike-dota-crack-diablo-fortnite-hack-keygen-keylogger-leagoflegend-lol-megaupload-monero-nocd-nordvpn-piratebay-popcorntime-starcraft-steam-tartiflette-tor-youporn' in 'trolldeb.deb'.

Et ensuite on l’installe :

$ sudo dpkg -i trolldeb.deb
Sélection du paquet bitcoin-bittorent-counterstrike-dota-crack-diablo-fortnite-hack-keygen-keylogger-leagoflegend-lol-megaupload-monero-nocd-nordvpn-piratebay-popcorntime-starcraft-steam-tartiflette-tor-youporn précédemment désélectionné.
(Lecture de la base de données... 269570 fichiers et répertoires déjà installés.)
Préparation du dépaquetage de trolldeb.deb ...
Dépaquetage de bitcoin-bittorent-counterstrike-dota-crack-diablo-fortnite-hack-keygen-keylogger-leagoflegend-lol-megaupload-monero-nocd-nordvpn-piratebay-popcorntime-starcraft-steam-tartiflette-tor-youporn (0.0) ...
Paramétrage de bitcoin-bittorent-counterstrike-dota-crack-diablo-fortnite-hack-keygen-keylogger-leagoflegend-lol-megaupload-monero-nocd-nordvpn-piratebay-popcorntime-starcraft-steam-tartiflette-tor-youporn (0.0) ...

Et voilà le travail ! Un beau paquet qui devrait faire bondir le RSSI :

$ dpkg -l | grep bitcoin
ii bitcoin-bittorent-counterstrike-dota-crack-diablo-fortnite-hack-keygen-keylogger-leagoflegend-lol-megaupload-monero-nocd-nordvpn-piratebay-popcorntime-starcraft-steam-tartiflette-tor-youporn 0.0 all Salut Sébastien, comment ça va ?