diff --git a/CMakeLists.txt b/CMakeLists.txt index e9b39bdd13e..306a2ae55f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ # CMAKE_MINIMUM_REQUIRED should be the first directive in the file: # https://cmake.org/cmake/help/latest/command/cmake_minimum_required.html -CMAKE_MINIMUM_REQUIRED(VERSION 2.8) +CMAKE_MINIMUM_REQUIRED(VERSION 3.16...3.29) PROJECT(HTTPD C) diff --git a/configure.in b/configure.in index 57f20ea824b..2ba4c6f7100 100644 --- a/configure.in +++ b/configure.in @@ -444,10 +444,10 @@ if test "${apu_found}" = "yes"; then # we need to add the APR includes to CPPFLAGS apu_ckver_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS `$apr_config --includes`" - APACHE_CHECK_APxVER([apu], 1, 3) + APACHE_CHECK_APxVER([apu], 1, 6) CPPFLAGS="$apu_ckver_CPPFLAGS" else - APACHE_CHECK_APxVER([apu], 1, 3) + APACHE_CHECK_APxVER([apu], 1, 6) fi fi diff --git a/docs/log-message-tags/next-number b/docs/log-message-tags/next-number index e5de12ffb20..37eec710963 100644 --- a/docs/log-message-tags/next-number +++ b/docs/log-message-tags/next-number @@ -1 +1 @@ -10546 +10547 diff --git a/docs/manual/developer/thread_safety.xml b/docs/manual/developer/thread_safety.xml index c74fd064bab..7c4b3b89023 100644 --- a/docs/manual/developer/thread_safety.xml +++ b/docs/manual/developer/thread_safety.xml @@ -152,11 +152,11 @@
strtok() and
@@ -210,7 +210,7 @@
href="http://www.imagemagick.com/www/changelog.html"
>Change log).
Ce document décrit l'installation, la configuration et - l'exécution d'Apache 2.&httpd.minor; sous Microsoft Windows. Si vous avez des + l'exécution du serveur HTTP Apache 2.&httpd.minor; sous Microsoft Windows. Si vous avez des questions après avoir lu la documentation, ou si vous avez rencontré des évènements particuliers ou des rapports d'erreur, vous pouvez consultez la liste de diffusion de la communauté des utilisateurs.
Dans ce document, nous supposons que vous installez une - distribution binaire d'Apache. Si vous voulez compiler Apache + distribution binaire d'httpd. Si vous voulez compiler httpd vous-même (par exemple pour aider au développement ou pour rechercher des bogues), référez-vous au document Compilation d'Apache pour Microsoft + href="win_compiling.html">Compilation de httpd pour Microsoft Windows.
La plate-forme Windows de base pour l'exécution d'Apache 2.&httpd.minor; est +
La plate-forme Windows de base pour l'exécution de httpd 2.&httpd.minor; est Windows 2000 ou supérieur. Veillez à toujours vous procurer et installer le dernier service pack afin d'éviter les bogues du système d'exploitation.
@@ -61,7 +61,7 @@Le projet du serveur HTTP Apache proprement dit ne fournit pas de distribution binaire mais seulement le code source. Certains membres @@ -83,12 +83,12 @@
La configuration d'Apache est enregistrée dans les fichiers du +
La configuration de httpd est enregistrée dans les fichiers du
sous-répertoire conf. Ce sont les même fichiers que
ceux utilisés pour configurer la version Unix, mais il y a quelques
- directives spécifiques à Apache pour Windows. Voir l'index des directives pour la liste
des directives disponibles.
Les principales spécificités d'Apache pour Windows sont :
+Les principales spécificités de httpd pour Windows sont :
Comme Apache pour Windows est un programme multithread, il - ne lance pas de processus séparé pour chaque requête, comme Apache +
Comme httpd pour Windows est un programme multithread, il + ne lance pas de processus séparé pour chaque requête, comme httpd peut le faire sous Unix. En fait, il n'y a en général que deux - processus Apache en exécution : un processus parent, et un + processus httpd en exécution : un processus parent, et un processus enfant qui traite les requêtes. Chaque requête est traitée par un thread séparé au sein du processus enfant.
@@ -139,7 +139,7 @@Les directives qui acceptent des noms de fichiers comme arguments doivent utiliser des noms de fichiers Windows et non - Unix. Cependant, comme Apache peut interpréter les anti-slashes + Unix. Cependant, comme httpd peut interpréter les anti-slashes comme des séquences d'échappement de caractères, vous devez absolument utiliser des slashes dans les noms de chemins à la place des anti-slashes.
Lors de son exécution, Apache n'a besoin d'un accès en +
Lors de son exécution, httpd n'a besoin d'un accès en écriture qu'au répertoire des journaux et à toute arborescence de répertoires de cache configurée. Suite au problème d'insensibilité - à la casse et au format de noms courts 8.3, Apache doit valider + à la casse et au format de noms courts 8.3, httpd doit valider tous les noms de chemins fournis. Cela signifie que chaque - répertoire qu'Apache évalue doit avoir les droits en lecture, + répertoire que httpd évalue doit avoir les droits en lecture, listage et parcours, et ceci depuis la racine jusqu'aux feuilles. Si Apache2.&httpd.minor; est installé dans C:\Program Files, le répertoire racine, Program Files et Apache2.&httpd.minor; doivent tous être visibles pour - Apache
Apache peut charger divers modules sans qu'il soit nécessaire - de recompiler le serveur. Si Apache est compilé +
httpd peut charger divers modules sans qu'il soit nécessaire
+ de recompiler le serveur. Si httpd est compilé
normalement, il va installer de nombreux modules optionnels dans
le répertoire \Apache2.&httpd.minor;\modules. Pour activer ces
modules ou d'autres modules, on doit utiliser la
@@ -196,16 +196,16 @@ RewriteRule "(.*)" "${lowercase:$1}" [R,L]
href="../mod/mod_so.html#creating">créer des modules
chargeables
Apache peut aussi charger des extensions ISAPI (Internet +
httpd peut aussi charger des extensions ISAPI (Internet Server Application Programming Interface), comme celles qu'utilise Microsoft IIS et d'autres serveurs Windows. Voir ici pour plus - d'informations. Notez qu'Apache ne peut pas + d'informations. Notez que httpd ne peut pas charger de filtres ISAPI, et que les gestionnaires ISAPI contenant des extensions de fonctionnalités Microsoft ne fonctionneront pas.
Pour les scripts CGI, la méthode qu'utilise Apache pour +
Pour les scripts CGI, la méthode qu'utilise httpd pour
déterminer l'interpréteur du script est configurable grâce à la
directive
Toute erreur survenant au cours du processus de démarrage
- d'Apache est enregistrée dans le journal des évènements de
+ de httpd est enregistrée dans le journal des évènements de
Windows si l'on est sous Windows NT. Ce mécanisme fonctionne comme
- une sauvegarde pour les situations où Apache n'est pas encore prêt
+ une sauvegarde pour les situations où httpd n'est pas encore prêt
à utiliser le fichier error.log. Vous pouvez
consulter le journal des évènements applicatifs Windows en
utilisant l'observateur d'évènements : Démarrage - Paramètres -
@@ -230,24 +230,24 @@ RewriteRule "(.*)" "${lowercase:$1}" [R,L]
Apache fournit un utilitaire nommé Apache Service Monitor - (Moniteur du service Apache). Grâce à lui, vous pouvez voir et gérer - l'état de tous les services Apache installés sur toutes les machines - du réseau. Pour pouvoir gérer un service Apache avec le moniteur, +
httpd fournit un utilitaire nommé Apache Service Monitor + (Moniteur du service httpd). Grâce à lui, vous pouvez voir et gérer + l'état de tous les services httpd installés sur toutes les machines + du réseau. Pour pouvoir gérer un service httpd avec le moniteur, vous devez d'abord installer le service (soit automatiquement au cours de l'installation, soit manuellement).
-Vous pouvez installer Apache en tant que service Windows NT à - partir de la ligne de commandes et depuis le sous-répertoire Apache +
Vous pouvez installer httpd en tant que service Windows NT à
+ partir de la ligne de commandes et depuis le sous-répertoire httpd
bin comme suit :
Si vous avez installé plusieurs services Apache sur votre +
Si vous avez installé plusieurs services httpd sur votre
ordinateur, vous devrez spécifier le nom du service que vous voulez
installer en utilisant la commande suivante (notez que si vous
spécifiez un nom durant l'installation, vous devrez aussi le
@@ -269,14 +269,14 @@ RewriteRule "(.*)" "${lowercase:$1}" [R,L]
Apache2.&httpd.minor; et le fichier de configuration sera censé
être conf\httpd.conf.
Supprimer un service Apache est très simple. Utilisez +
Supprimer un service httpd est très simple. Utilisez simplement :
On peut spécifier un service Apache particulier en utilisant +
On peut spécifier un service httpd particulier en utilisant :
Normalement, le démarrage, le redémarrage et l'arrêt d'un
- service Apache s'effectuent via le Moniteur de Service Apache, ou en
+ service httpd s'effectuent via le Moniteur de Service httpd, ou en
utilisant des commandes telles que NET START Apache2.&httpd.minor; et
NET STOP Apache2.&httpd.minor;, ou encore via le gestionnaire de
- services standard de Windows. Avant de démarrer Apache en tant que
+ services standard de Windows. Avant de démarrer httpd en tant que
service dans quelque but que ce soit, vous devez tester le fichier
de configuration du service en utilisant :
Vous pouvez aussi contrôler un service Apache à l'aide de ses +
Vous pouvez aussi contrôler un service httpd à l'aide de ses options de ligne de commande. Avec cette méthode, pour démarrer un - service Apache installé, vous utiliserez :
+ service httpd installé, vous utiliserez :Pour arrêter un service Apache via les options de lignes de +
Pour arrêter un service httpd via les options de lignes de commande, utilisez ceci :
Par défaut, tous les services Apache sont configurés pour +
Par défaut, tous les services httpd sont configurés pour
s'exécuter sous l'utilisateur system (le compte
LocalSystem). Le compte LocalSystem n'a
pas de privilèges sur votre réseau, que ce soit via un mécanisme
@@ -332,14 +332,14 @@ RewriteRule "(.*)" "${lowercase:$1}" [R,L]
élevés en local.
LocalSystem ! Si Apache doit pouvoir accéder
- à des ressources réseau, créez un compte séparé pour Apache comme
+ au compte LocalSystem ! Si httpd doit pouvoir accéder
+ à des ressources réseau, créez un compte séparé pour httpd comme
indiqué ci-dessous.Il est fortement fortement conseillé aux utilisateurs de créer un - compte séparé pour exécuter le(s) service(s) Apache, et même + compte séparé pour exécuter le(s) service(s) httpd, et même obligatoire si vous devez accéder à des ressources réseau via - Apache.
+ httpd.logs, sur lequel l'utilisateur doit
avoir au moins les droits de modification (RWXD).Si vous permettez à ce compte de se connecter en tant qu'utilisateur et service, vous pouvez ouvrir une session sous ce compte et vérifier s'il a bien le droit d'exécuter les scripts, de - lire les pages web, et si vous pouvez démarrer Apache à partir d'une + lire les pages web, et si vous pouvez démarrer httpd à partir d'une console Windows. Si tout fonctionne, et si vous avez suivi les - étapes ci-dessus, Apache devrait s'exécuter en tant que service sans + étapes ci-dessus, httpd devrait s'exécuter en tant que service sans problème.
Lorsqu'Apache démarre en tant que service, il se peut que vous +
Lorsqu'httpd démarre en tant que service, il se peut que vous obteniez un message d'erreur du Gestionnaire de Services Windows. - Par exemple, si vous essayez de démarrer Apache en utilisant + Par exemple, si vous essayez de démarrer httpd en utilisant l'applet Services du Panneau de configuration de Windows, vous pouvez obtenir le message suivant :
@@ -398,9 +398,9 @@ RewriteRule "(.*)" "${lowercase:$1}" [R,L]Vous obtiendrez cette erreur à caractère général pour tout - problème survenant au cours du démarrage du service Apache. Afin de + problème survenant au cours du démarrage du service httpd. Afin de déterminer exactement la cause du problème, vous devez suivre les - instructions permettant d'exécuter Apache pour Windows depuis la + instructions permettant d'exécuter httpd pour Windows depuis la ligne de commande.
Si vous rencontrez des problèmes avec le service, il est @@ -411,44 +411,44 @@ RewriteRule "(.*)" "${lowercase:$1}" [R,L]
Il est en général recommandé d'exécuter Apache en tant que +
Il est en général recommandé d'exécuter httpd en tant que service, mais il est parfois plus simple d'utiliser la ligne de commande, en particulier au cours de la configuration initiale et les tests.
-Pour exécuter Apache depuis la ligne de commande et en tant +
Pour exécuter httpd depuis la ligne de commande et en tant qu'application de console, utilisez la commande suivante :
Apache va démarrer, et continuera son exécution jusqu'à ce qu'on +
httpd va démarrer, et continuera son exécution jusqu'à ce qu'on l'arrête en tapant Ctrl-C.
-Vous pouvez également démarrer Apache via le raccourci "Démarrer
- Apache dans une console" placé dans Vous pouvez également démarrer httpd via le raccourci "Démarrer
+ httpd dans une console" placé dans Si Apache s'exécute en tant que service, vous pouvez l'arrêter en
+ Si httpd s'exécute en tant que service, vous pouvez l'arrêter en
ouvrant une autre console et en entrant : Plutôt que de lancer Apache à partir d'une console, il est
+ Plutôt que de lancer httpd à partir d'une console, il est
préférable de l'exécuter en tant que service car dans ce cas, il
termine proprement les opérations en cours avant de s'éteindre.Démarrer -->
+ Démarrer -->
Programmes --> Apache HTTP Server 2.&httpd.minor;.xx --> Control Apache
Server au cours de l'installation. Ceci va
- ouvrir une console Windows, et y démarrer Apache.
- Si vous n'avez pas installé Apache en tant que service, la
- fenêtre Windows restera ouverte jusqu'à ce que vous arrêtiez Apache
+ ouvrir une console Windows, et y démarrer httpd.
+ Si vous n'avez pas installé httpd en tant que service, la
+ fenêtre Windows restera ouverte jusqu'à ce que vous arrêtiez httpd
en tapant Ctrl-C dans cette fenêtre. Le serveur va alors s'arrêter
au bout de quelques secondes. Cependant, si vous avez installé
- Apache en tant que service, c'est ce dernier que le raccourci
- ci-dessus va lancer. Si le service Apache est déjà en cours
+ httpd en tant que service, c'est ce dernier que le raccourci
+ ci-dessus va lancer. Si le service httpd est déjà en cours
d'exécution, le raccourci va rester sans effet.
Vous pouvez aussi redémarrer Apache. Ceci le force à recharger +
Vous pouvez aussi redémarrer httpd. Ceci le force à recharger son fichier de configuration. Toute opération en cours peut être - achevée sans interruption. Pour redémarrer Apache, vous pouvez soit + achevée sans interruption. Pour redémarrer httpd, vous pouvez soit taper Control-Break dans la fenêtre de console que vous avez utilisée pour le démarrer, soit entrer :
@@ -469,20 +469,20 @@ RewriteRule "(.*)" "${lowercase:$1}" [R,L]si le serveur s'exécute en tant que service.
kill -TERM pid et
kill -USR1 pid. L'option de ligne de commande
-k a été choisie à titre de rapprochement avec la
commande kill utilisée sous Unix.Si la fenêtre de la console Apache se ferme immédiatement ou - inopinément après le démarrage d'Apache, ouvrez une console Windows +
Si la fenêtre de la console httpd se ferme immédiatement ou
+ inopinément après le démarrage de httpd, ouvrez une console Windows
depuis le menu Démarrer --> Programmes. Placez-vous dans le
- répertoire d'installation d'Apache, tapez la commande
+ répertoire d'installation de httpd, tapez la commande
httpd.exe, et observez le message d'erreur. Allez
ensuite dans le répertoire des journaux, et visualisez le fichier
error.log pour détecter d'éventuelles erreurs de
- configuration. Si Apache a été installé dans C:\Program
+ configuration. Si httpd a été installé dans C:\Program
Files\Apache Software Foundation\Apache2.&httpd.minor;\, vous
pouvez entrer ce qui suit :
Attendez ensuite qu'Apache s'arrête ou tapez Ctrl-C. Entrez alors +
Attendez ensuite que httpd s'arrête ou tapez Ctrl-C. Entrez alors la commande suivante :
Lorsqu'on travaille avec Apache, il est important de comprendre +
Lorsqu'on travaille avec httpd, il est important de comprendre comment ce dernier trouve son fichier de configuration. Vous pouvez spécifier un fichier de configuration à partir de la ligne de commande de deux façons :
@@ -523,7 +523,7 @@ RewriteRule "(.*)" "${lowercase:$1}" [R,L]L'option -n permet de spécifier le service
- Apache installé dont le fichier de configuration doit être utilisé
+ httpd installé dont le fichier de configuration doit être utilisé
:
Si vous ne spécifiez aucun fichier de configuration à l'aide des
- options -f ou -n, Apache utilisera le nom
+ options -f ou -n, httpd utilisera le nom
du fichier de configuration compilé dans le serveur, en général
conf\httpd.conf. Ce chemin codé en dur est relatif au
répertoire d'installation. Vous pouvez vérifier ce chemin à partir
de la valeur de l'étiquette SERVER_CONFIG_FILE en
- invoquant Apache avec l'option -V, comme ceci :
-V, comme ceci :
Apache va ensuite essayer de déterminer la valeur de son +
httpd va ensuite essayer de déterminer la valeur de son
Si vous n'avez pas effectué d'installation binaire, dans certains - scénarios, Apache va signaler l'absence de cette clé de registre. + scénarios, httpd va signaler l'absence de cette clé de registre. On peut passer outre cet avertissement si le serveur a été en mesure de trouver son fichier de configuration d'une autre manière.
La valeur de cette clé correspond au répertoire Une fois Apache démarré (soit à partir d'une console Windows,
+ Une fois httpd démarré (soit à partir d'une console Windows,
soit en tant que service), ce dernier va se mettre à l'écoute sur
le port 80 (à moins que vous ayiez modifié la directive conf. Lors de son démarrage, Apache lit
+ sous-répertoire conf. Lors de son démarrage, httpd lit
le fichier httpd.conf à partir de ce répertoire. Si ce
fichier contient une directive httpd.conf afin de refléter la nouvelle
@@ -594,11 +594,11 @@ RewriteRule "(.*)" "${lowercase:$1}" [R,L]
Apache devrait renvoyer une page de bienvenue et vous devriez +
httpd devrait renvoyer une page de bienvenue et vous devriez
voir s'afficher "It Works!". Si rien ne se passe ou si vous obtenez
une erreur, consultez le fichier error.log dans le
sous-répertoire logs. Si votre serveur n'est pas
@@ -618,7 +618,7 @@ RewriteRule "(.*)" "${lowercase:$1}" [R,L]
http://127.0.0.1/
-
Si Apache écoute un port non standard, vous devez le préciser +
Si httpd écoute un port non standard, vous devez le préciser explicitement dans l'URL :
Après que votre installation de base fonctionne, vous devez la
configurer correctement en éditant les fichiers du sous-répertoire
conf. Encore une fois, si vous modifiez la
- configuration du service Apache sous Windows NT, essayez d'abord de
+ configuration du service httpd sous Windows NT, essayez d'abord de
redémarrer le service depuis la ligne de commande afin de vous
assurer de l'absence d'erreur.
Comme Apache ne peut pas partager le même port +
Comme httpd ne peut pas partager le même port avec d'autres applications TCP/IP, il se peut que vous soyez amené à arrêter, désinstaller ou reconfigurer certains services avant de - démarrer Apache. Ces services entrant en conflit avec Apache + démarrer httpd. Ces services entrant en conflit avec httpd comprennent les autres serveurs WWW, certaines implémentations de pare-feu, et même certaines applications client (comme Skype) qui utilisent le port 80 afin de contourner les pare-feu.
@@ -701,7 +701,7 @@ Alias "/images2/" "//imagehost2/www/images/"Lorsqu'Apache s'exécute en tant que service, vous devez créer un +
Lorsque Apache s'exécute en tant que service, vous devez créer un compte spécifique afin de pouvoir accéder aux ressources réseau, comme décrit ci-dessus.
apxs est un utilitaire permettant de compiler et
+
apxs vous le signalera. Vous pouvez aussi vérifier
+
Le module apxs, via le mécanisme DSO :
Les arguments fichiers peuvent correspondre à un
fichier source C (.c), un fichier objet (.o) ou même une archive de
- bibliothèques (.a). L'utilitaire apxs reconnaît
+ bibliothèques (.a). L'utilitaire -fpic. Pour les autres compilateurs C, consultez leur
- page de manuel, ou vérifiez les drapeaux qu'apxs
+ page de manuel, ou vérifiez les drapeaux qu'
Pour plus de détails à propos du support DSO dans Apache, lire la
@@ -133,7 +137,7 @@
modèles). Utilisez cette option pour spécifier de manière
explicite le nom du module. Pour l'option -g, cette
option est nécessaire ; pour l'option -i,
- l'utilitaire apxs tente de déterminer le nom du
+ l'utilitaire httpd qui chargera
votre module. Ajoutez par exemple
dans vos propres Makefiles si vous devez accéder manuellement @@ -284,35 +290,41 @@ Apache à l'exécution, via la commande suivante :
Vous devez ensuite vérifier la configuration d'Apache en vous
assurant qu'une directive apxs propose une méthode automatique d'installation de
+ httpd.conf en conséquence. Pour bénéficier de
cette automatisation, utilisez la commande suivante :
Une ligne contenant
est alors ajoutée au fichier de configuration si ce n'est pas
@@ -320,7 +332,9 @@
utilisez l'option -A comme suit :
Pour un test rapide du mécanisme apxs, vous pouvez créer un @@ -328,35 +342,39 @@ correspondant via :
Vous pouvez ensuite compiler immédiatement ce module exemple en objet partagé et le charger dans le serveur Apache :
Le script configure permet de configurer
+
Le script Vous devez appeler le script Vous devez appeler le script Les options suivantes affectent le comportement du script
- Les options suivantes permettent de définir avec précision le
comportement du programme Certaines variables d'environnement permettent de modifier les
- choix effectués par Cette page de manuel ne décrit que les arguments de la ligne de
commande. Pour plus de détails à propos des directives nécessaires à
diff --git a/docs/manual/programs/logresolve.xml.fr b/docs/manual/programs/logresolve.xml.fr
index 714b4ca7f63..6fd25f89c41 100644
--- a/docs/manual/programs/logresolve.xml.fr
+++ b/docs/manual/programs/logresolve.xml.fr
@@ -1,7 +1,7 @@
-
+
@@ -30,7 +30,7 @@
fichiers journaux d'Apache
configure depuis le
+ ./configure [OPTION]...
@@ -69,7 +69,7 @@
configure.
-C-n--no-createconfigure s'exécute normalement, mais
+ --srcdir=DIRconfigure, ou le répertoire parent.--silent--quiet--enable-foo, et si
- foo n'existe pas, configure ne le
+ foo n'existe pas, configure considèrera fichier-module
+ configure le chemin du script
+ apr-config. Vous pouvez spécifier le chemin absolu
et le nom ou le répertoire d'installation de l'APR.
apr-config doit se trouver dans ce répertoire ou
@@ -557,7 +557,7 @@
distribution des sources de httpd et sont compilés
automatiquement avec le serveur HTTP. Si vous voulez utiliser
des APU déjà installés à la place, vous devez indiquer à
- configure le chemin du script
+ apu-config. Vous pouvez spécifier le chemin absolu
et le nom ou le répertoire d'installation des APU.
apu-config doit se trouver dans ce répertoire ou
@@ -565,12 +565,12 @@
--with-ssl=REPconfigure recherche une installation d'OpenSSL.
+ --with-z=REPconfigure recherche automatiquement une
+ zlib installée si la configuration de
vos sources en nécessite une (par exemple lorsque
--with-gdbm[=chemin]configure va rechercher les fichiers d'en-têtes et
+ configure recherchera les fichiers concernés dans
+ chemin/lib et
chemin/include. En fait,
chemin permet de spécifier plusieurs chemins
@@ -677,7 +677,8 @@
suexecconfigure, ou d'aider ce dernier à
+ choix effectués par htdigest permet de créer et maintenir les fichiers
+ htdigest.logresolve est un programme agissant après
+ -clogresolve effectue certaines
+logresolve effectue une recherche DNS sur ce
+adresse IP,
mod_rewrite doit supprimer les séquences d'échappement
+
Dans l'exemple ci-dessus, la règle ne réécrit
pas la requête. La cible de réécriture "-"
-indique à mod_rewrite de transmettre la requête sans
+indique à .example.org. Sa
@@ -562,10 +562,25 @@ bien que .JPG seront acceptés.
Par défaut, les caractères spéciaux, comme & et
-?, sont convertis en leur équivalent hexadécimal pour les règles
-qui génèrent des redirections externes. Le drapeau [NE] permet d'éviter cette
-conversion.
Par défaut, lorsqu’une directive
A-Z, a-z,
+ 0-9$-_.+!*'(),:;@&=/~Par exemple, # est converti en %23 et
+? en %3F. Le caractère % est aussi
+échappé (vers %25), ce qui signifie que tout caractère codé avec
+pourcentage déjà présent dans la substitution sera doublement encodé.
Utiliser le drapeau [NE] empêche cet échappement, ce qui permet de
+transmettre sans modification vers l’URL de redirection des caractères comme
+# et ?.
Dans un contexte de niveau répertoire, n'utilisez que -
(tiret) comme substitution, dans toute la séquence de réécriture de
-mod_rewrite, sinon le type MIME défini avec ce drapeau
+L pour terminer la séquence
-courante de réécriture de mod_rewrite.
Ce document est un complément de la documentation de référence du module
Dans l'exemple interne, on a utilisé mod_rewrite afin
+ href="#old-to-new-intern">interne, on a utilisé
Cet exemple utilise une fonctionnalité souvent méconnue de
- mod_rewrite, en tirant avantage de l'ordre d'exécution du jeu de
- règles. En particulier, mod_rewrite évalue la partie gauche des
+
Pour y parvenir, il vaut mieux se passer de mod_rewrite, et utiliser +
Pour y parvenir, il vaut mieux se passer de
Si, pour une raison particulière, vous voulez tout de même utiliser
-mod_rewrite - dans le cas, par exemple, où vous avez besoin
+
Ce document passe en revue certains détails techniques à propos du -module mod_rewrite et de la mise en correspondance des URLs
+modulemod_rewrite agit dans deux de ces phases (ou accroches - hooks - +
Tout d'abord, il utilise le hook traduction URL vers nom de @@ -78,7 +78,7 @@ correspondance type="section">Directory) sont appliquées. Ce processus s'exécute au cours de la phase Fixup.
-Dans tous ces cas, mod_rewrite réécrit le +
Dans tous ces cas, REQUEST_URI soit vers une nouvelle URL, soit vers un
nom de fichier.
.htaccess et les sections
Directory), les règles de réécriture s'appliquent après
la traduction de l'URL en nom de fichier. C'est pourquoi le chemin
- URL auquel mod_rewrite compare initialement les directives
+ URL auquel Pour une étude plus approfondie de la manière dont mod_rewrite +
Pour une étude plus approfondie de la manière dont
Maintenant, quand mod_rewrite se lance dans ces deux phases de +
Maintenant, quand
L'URL est tout d'abord comparée au
Modèle de chaque règle. Lorsqu'une règle ne s'applique
- pas, mod_rewrite stoppe immédiatement le traitement de cette règle
+ pas,
www. et si c'est le cas, la réécriture est annulée.
Comme c'est le cas pour de nombreuses techniques discutées dans ce
-document, mod_rewrite n'est vraiment pas la meilleure méthode pour
+document, mod_rewrite fonctionne correctement ; la seconde moitié
- configure mod_rewrite pour effectuer le travail
+
Comme mod_rewrite s'exécute avant tout autre module
+
Comme mod_alias), il faut lui
ordonner explicitement d'ignorer toute URL susceptible d'être
traitée par ces autres modules. Et comme ces règles auraient sinon
court-circuité toute directive ScriptAlias, nous devons
- faire en sorte que mod_rewrite déclare explicitement
+ faire en sorte que
The SSL Protocol Version 3.0, 1996. See http://www.netscape.com/eng/ssl3/draft302.txt.
The TLS Protocol Version 1.0, diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 09770fa1a57..ccd504d8e82 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -736,6 +736,7 @@ * 20211221.28 (2.5.1-dev) Add dav_get_base_path() to mod_dav * 20211221.29 (2.5.1-dev) Add ap_set_time_process_request() to scoreboard.h * 20211221.30 (2.5.1-dev) Add ap_stat_check() to httpd.h + * 20211221.31 (2.5.1-dev) Add ap_*_timingsafe() to httpd.h */ #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */ @@ -743,7 +744,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20211221 #endif -#define MODULE_MAGIC_NUMBER_MINOR 30 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 31 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/include/httpd.h b/include/httpd.h index b12b7e4e21b..03376db9958 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -2261,6 +2261,54 @@ AP_DECLARE(int) ap_ind(const char *str, char c); /* Sigh... */ */ AP_DECLARE(int) ap_rind(const char *str, char c); +/** + * Check whether two buffers of equal size have the same content, using a + * constant time algorithm (branch-less with regard to the content of the + * buffers and an execution time solely dependent on the number of bytes + * compared, not the bytes themselves). + * + * @param buf1 first buffer to compare + * @param buf2 second buffer to compare + * @param n number of bytes to compare + * @return 1 if equal, 0 otherwise + */ +AP_DECLARE(int) ap_memeq_timingsafe(const void *buf1, const void *buf2, + apr_size_t n); + +/** + * Check whether two NUL-terminated strings have the same content, using a + * constant time algorithm (branch-less with regard to the content of the + * secret string and an execution time solely dependent on the length of + * the non-secret string). The secret string of the two should be set in + * the first parameter \c sec1 to avoid leaking its length. + * + * @param sec1 first string to compare (the secret one) + * @param str2 second string to compare + * @return 1 if equal, 0 otherwise + * @remark The function will compare as much characters as there are in + * \c str2, so the length of \c str2 might leak through side channel, + * while the length of \c sec1 does not. + */ +AP_DECLARE(int) ap_streq_timingsafe(const char *sec1, const char *str2); + +/** + * Check whether two NUL-terminated strings have the same content, up to \c n + * characters, using a constant time algorithm (branch-less with regard to the + * content of the secret string and an execution time solely dependent on the + * length of the non-secret string or \c n). The secret string of the two + * should be set in the first parameter \c sec1 to avoid leaking its length. + * + * @param sec1 secret string to compare + * @param str2 string to compare with + * @param n max number of characters to compare + * @return 1 if equal, 0 otherwise + * @remark The function will compare as much characters as there are in + * \c str2 if it's less than \c n, so the length of \c str2 might + * leak through side channel, while the length of \c sec1 does not. + */ +AP_DECLARE(int) ap_strneq_timingsafe(const char *sec1, const char *str2, + apr_size_t n); + /** * Given a string, replace any bare " with \\" . * @param p The pool to allocate memory from diff --git a/modules/aaa/mod_auth_digest.c b/modules/aaa/mod_auth_digest.c index c15514b9eac..fb4d26306be 100644 --- a/modules/aaa/mod_auth_digest.c +++ b/modules/aaa/mod_auth_digest.c @@ -99,10 +99,17 @@ typedef struct digest_config_struct { #define DFLT_NONCE_LIFE apr_time_from_sec(300) #define NEXTNONCE_DELTA apr_time_from_sec(30) - +/* The server nonce has fixed length and is the concatenation of: + * base64(apr_time_t timestamp) + hex(SHA1(realm+time[+opaque])) */ #define NONCE_TIME_LEN (((sizeof(apr_time_t)+2)/3)*4) #define NONCE_HASH_LEN (2*APR_SHA1_DIGESTSIZE) #define NONCE_LEN (int )(NONCE_TIME_LEN + NONCE_HASH_LEN) +/* Evaluates to true if nonce string is valid. Since the time part of + * the nonce is a base64 encoding of an apr_time_t (8 bytes), it + * must end with a '='. */ +#define VALID_NONCE(n_) ((n_) && strlen((n_)) == NONCE_LEN && (n_)[NONCE_TIME_LEN - 1] == '=') + +#define MD5_DIGEST_LEN (2*APR_MD5_DIGESTSIZE) /* ignoring trailing \0 */ #define SECRET_LEN 20 #define RETAINED_DATA_ID "mod_auth_digest" @@ -1013,8 +1020,9 @@ static int get_digest_rec(request_rec *r, digest_header_rec *resp) resp->nonce_count = apr_pstrdup(r->pool, value); } - if (!resp->username || !resp->realm || !resp->nonce || !resp->uri - || !resp->digest + if (!resp->username || !resp->realm || !resp->uri + || !VALID_NONCE(resp->nonce) + || !resp->digest || strlen(resp->digest) != MD5_DIGEST_LEN || (resp->message_qop && (!resp->cnonce || !resp->nonce_count))) { resp->auth_hdr_sts = INVALID; return !OK; @@ -1066,14 +1074,9 @@ static int parse_hdr_and_update_nc(request_rec *r) } -/* - * Nonce generation code - */ - -/* The hash part of the nonce is a SHA-1 hash of the time, realm, server host - * and port, opaque, and our secret. - */ -static void gen_nonce_hash(char *hash, const char *timestr, const char *opaque, +/* Writes the hash part of the server nonce to hash, which must be of + * minimum size (NONCE_HASH_LEN+1). */ +static void gen_nonce_hash(char hash[NONCE_HASH_LEN+1], const char *timestr, const char *opaque, const server_rec *server, const digest_config_rec *conf, const char *realm) @@ -1427,19 +1430,6 @@ static int check_nonce(request_rec *r, digest_header_rec *resp, time_rec nonce_time; char tmp, hash[NONCE_HASH_LEN+1]; - /* Since the time part of the nonce is a base64 encoding of an - * apr_time_t (8 bytes), it should end with a '=', fail early otherwise. - */ - if (strlen(resp->nonce) != NONCE_LEN - || resp->nonce[NONCE_TIME_LEN - 1] != '=') { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01775) - "invalid nonce '%s' received - length is not %d " - "or time encoding is incorrect", - resp->nonce, NONCE_LEN); - note_digest_auth_failure(r, conf, resp, 1); - return HTTP_UNAUTHORIZED; - } - tmp = resp->nonce[NONCE_TIME_LEN]; resp->nonce[NONCE_TIME_LEN] = '\0'; apr_base64_decode_binary(nonce_time.arr, resp->nonce); @@ -1447,7 +1437,7 @@ static int check_nonce(request_rec *r, digest_header_rec *resp, resp->nonce[NONCE_TIME_LEN] = tmp; resp->nonce_time = nonce_time.time; - if (strcmp(hash, resp->nonce+NONCE_TIME_LEN)) { + if (!ap_memeq_timingsafe(hash, resp->nonce+NONCE_TIME_LEN, NONCE_HASH_LEN)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01776) "invalid nonce %s received - hash is not %s", resp->nonce, hash); @@ -1778,7 +1768,7 @@ static int authenticate_digest_user(request_rec *r) if (resp->message_qop == NULL) { /* old (rfc-2069) style digest */ - if (strcmp(resp->digest, old_digest(r, resp))) { + if (!ap_memeq_timingsafe(old_digest(r, resp), resp->digest, MD5_DIGEST_LEN)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01792) "user %s: password mismatch: %s", r->user, r->uri); @@ -1813,7 +1803,7 @@ static int authenticate_digest_user(request_rec *r) /* we failed to allocate a client struct */ return HTTP_INTERNAL_SERVER_ERROR; } - if (strcmp(resp->digest, exp_digest)) { + if (!ap_memeq_timingsafe(exp_digest, resp->digest, MD5_DIGEST_LEN)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01794) "user %s: password mismatch: %s", r->user, r->uri); diff --git a/modules/aaa/mod_authn_socache.c b/modules/aaa/mod_authn_socache.c index 92202b16b20..c5461d8f624 100644 --- a/modules/aaa/mod_authn_socache.c +++ b/modules/aaa/mod_authn_socache.c @@ -265,11 +265,10 @@ static const command_rec authn_cache_cmds[] = static const char *construct_key(request_rec *r, const char *context, const char *user, const char *realm) { + const char *slash = ap_strrchr_c(r->uri, '/'); /* handle "special" context values */ - if (!strcmp(context, directory)) { - /* FIXME: are we at risk of this blowing up? */ + if (!strcmp(context, directory) && slash) { char *new_context; - char *slash = strrchr(r->uri, '/'); new_context = apr_palloc(r->pool, slash - r->uri + strlen(r->server->server_hostname) + 1); strcpy(new_context, r->server->server_hostname); diff --git a/modules/dav/lock/locks.c b/modules/dav/lock/locks.c index e85e288b326..b36f846d796 100644 --- a/modules/dav/lock/locks.c +++ b/modules/dav/lock/locks.c @@ -1190,13 +1190,13 @@ static dav_error * dav_generic_refresh_locks(dav_lockdb *lockdb, } if (dav_generic_do_refresh(dp_scan, ltl, new_time)) { /* the lock was refreshed. return the lock. */ - newlock = dav_generic_alloc_lock(lockdb, ip->key, dp->locktoken); + newlock = dav_generic_alloc_lock(lockdb, ip->key, dp_scan->locktoken); newlock->is_locknull = !resource->exists; - newlock->scope = dp->f.scope; - newlock->type = dp->f.type; - newlock->depth = dp->f.depth; - newlock->timeout = dp->f.timeout; - newlock->owner = dp->owner; + newlock->scope = dp_scan->f.scope; + newlock->type = dp_scan->f.type; + newlock->depth = dp_scan->f.depth; + newlock->timeout = dp_scan->f.timeout; + newlock->owner = dp_scan->owner; newlock->auth_user = dp_scan->auth_user; newlock->next = *locks; diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c index 004c3c2a6bf..8e5f76102ea 100644 --- a/modules/http/http_filters.c +++ b/modules/http/http_filters.c @@ -990,6 +990,11 @@ static apr_status_t validate_status_line(request_rec *r) r->status_line = apr_pstrcat(r->pool, r->status_line, " ", NULL); return APR_EGENERAL; } + /* Check for newlines and control characters */ + if (len > 4 && *ap_scan_http_field_content(r->status_line + 4)) { + r->status_line = NULL; + return APR_EGENERAL; + } return APR_SUCCESS; } return APR_EGENERAL; diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c index 638682a375c..75b41110b31 100644 --- a/modules/mappers/mod_rewrite.c +++ b/modules/mappers/mod_rewrite.c @@ -3686,12 +3686,17 @@ static const char *cmd_rewritecond(cmd_parms *cmd, void *in_dconf, newcond->regexp = regexp; } else if (newcond->ptype == CONDPAT_AP_EXPR) { + int in_htaccess = cmd->pool == cmd->temp_pool; unsigned int flags = newcond->flags & CONDFLAG_NOVARY ? AP_EXPR_FLAG_DONT_VARY : 0; + /* Use restricted ap_expr() parser in htaccess context. */ + if (in_htaccess) flags |= AP_EXPR_FLAG_RESTRICTED; newcond->expr = ap_expr_parse_cmd(cmd, a2, flags, &err, NULL); if (err) return apr_psprintf(cmd->pool, "RewriteCond: cannot compile " - "expression \"%s\": %s", a2, err); + "expression%s \"%s\" %s", + in_htaccess ? " in htaccess context" : "", + a2, err); } return NULL; diff --git a/modules/md/md_ocsp.c b/modules/md/md_ocsp.c index 74dd49058a8..aee799a7b39 100644 --- a/modules/md/md_ocsp.c +++ b/modules/md/md_ocsp.c @@ -46,7 +46,21 @@ #include "md_ocsp.h" #define MD_OCSP_ID_LENGTH SHA_DIGEST_LENGTH - + +/* Max acceptable OCSP response size (DER-encoded responses are typically <2 KiB) */ +#define MD_OCSP_MAX_RESPONSE_LEN (64 * 1024) +/* Timeout for OCSP responses */ +#define MD_OCSP_DEFAULT_TIMEOUT apr_time_from_sec(60) +/* Timeout for connecting to OCSP servers */ +#define MD_OCSP_CONNECT_TIMEOUT apr_time_from_sec(30) +/* + * Below this throughput in bytes per second an OCSP response is regarded as + * stalled. + */ +#define MD_OCSP_STALLING_BYTES 10 +/* Maximum duration for a stalled period during an OCSP response */ +#define MD_OCSP_STALLING_TIME apr_time_from_sec(30) + struct md_ocsp_reg_t { apr_pool_t *p; md_store_t *store; @@ -901,6 +915,12 @@ void md_ocsp_renew(md_ocsp_reg_t *reg, apr_pool_t *p, apr_pool_t *ptemp, apr_tim rv = md_http_create(&http, ptemp, reg->user_agent, reg->proxy_url); if (APR_SUCCESS != rv) goto cleanup; + + md_http_set_response_limit(http, MD_OCSP_MAX_RESPONSE_LEN); + md_http_set_timeout_default(http, MD_OCSP_DEFAULT_TIMEOUT); + md_http_set_connect_timeout_default(http, MD_OCSP_CONNECT_TIMEOUT); + md_http_set_stalling_default(http, MD_OCSP_STALLING_BYTES, + MD_OCSP_STALLING_TIME); rv = md_http_multi_perform(http, next_todo, &ctx); diff --git a/modules/metadata/mod_setenvif.c b/modules/metadata/mod_setenvif.c index 97e6106d966..89dd394e74d 100644 --- a/modules/metadata/mod_setenvif.c +++ b/modules/metadata/mod_setenvif.c @@ -435,6 +435,12 @@ static const char *add_setenvifexpr(cmd_parms *cmd, void *mconfig, sei_cfg_rec *sconf; sei_entry *new; const char *err; + unsigned int flags = 0; + + /* Use restricted ap_expr() parser in htaccess context. */ + if (cmd->pool == cmd->temp_pool) { + flags |= AP_EXPR_FLAG_RESTRICTED; + } /* * Determine from our context into which record to put the entry. @@ -458,7 +464,7 @@ static const char *add_setenvifexpr(cmd_parms *cmd, void *mconfig, new->regex = NULL; new->pattern = NULL; new->preg = NULL; - new->expr = ap_expr_parse_cmd(cmd, expr, 0, &err, NULL); + new->expr = ap_expr_parse_cmd(cmd, expr, flags, &err, NULL); if (err) return apr_psprintf(cmd->pool, "Could not parse expression \"%s\": %s", expr, err); diff --git a/modules/proxy/ajp_header.c b/modules/proxy/ajp_header.c index 00db324e426..334d0aebb12 100644 --- a/modules/proxy/ajp_header.c +++ b/modules/proxy/ajp_header.c @@ -835,6 +835,11 @@ apr_status_t ajp_parse_data(request_rec *r, ajp_msg_t *msg, * 1 : The last byte of this message always seems to be * 0x00 and is not part of the chunk. */ + if (msg->len < AJP_HEADER_LEN + AJP_HEADER_SZ_LEN + 1 + 1) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10546) + "ajp_parse_data: Message too small"); + return AJP_EBAD_HEADER; + } expected_len = msg->len - (AJP_HEADER_LEN + AJP_HEADER_SZ_LEN + 1 + 1); if (*len != expected_len) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00998) diff --git a/modules/proxy/ajp_msg.c b/modules/proxy/ajp_msg.c index b5b3f2c07bf..349b5d7e08c 100644 --- a/modules/proxy/ajp_msg.c +++ b/modules/proxy/ajp_msg.c @@ -166,11 +166,11 @@ apr_status_t ajp_msg_check_header(ajp_msg_t *msg, apr_size_t *len) msglen = ((head[2] & 0xff) << 8); msglen += (head[3] & 0xFF); - if (msglen > msg->max_size) { + if (msglen > (msg->max_size - AJP_HEADER_LEN)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(01081) "ajp_msg_check_header() incoming message is " "too big %" APR_SIZE_T_FMT ", max is %" APR_SIZE_T_FMT, - msglen, msg->max_size); + msglen, msg->max_size - AJP_HEADER_LEN); return AJP_ETOBIG; } @@ -395,7 +395,7 @@ apr_status_t ajp_msg_get_uint32(ajp_msg_t *msg, apr_uint32_t *rvalue) { apr_uint32_t value; - if ((msg->pos + 3) > msg->len) { + if ((msg->pos + 3) >= msg->len) { return ajp_log_overflow(msg, "ajp_msg_get_uint32"); } @@ -420,7 +420,7 @@ apr_status_t ajp_msg_get_uint16(ajp_msg_t *msg, apr_uint16_t *rvalue) { apr_uint16_t value; - if ((msg->pos + 1) > msg->len) { + if ((msg->pos + 1) >= msg->len) { return ajp_log_overflow(msg, "ajp_msg_get_uint16"); } @@ -443,7 +443,7 @@ apr_status_t ajp_msg_peek_uint16(ajp_msg_t *msg, apr_uint16_t *rvalue) { apr_uint16_t value; - if ((msg->pos + 1) > msg->len) { + if ((msg->pos + 1) >= msg->len) { return ajp_log_overflow(msg, "ajp_msg_peek_uint16"); } @@ -464,7 +464,7 @@ apr_status_t ajp_msg_peek_uint16(ajp_msg_t *msg, apr_uint16_t *rvalue) */ apr_status_t ajp_msg_peek_uint8(ajp_msg_t *msg, apr_byte_t *rvalue) { - if (msg->pos > msg->len) { + if (msg->pos >= msg->len) { return ajp_log_overflow(msg, "ajp_msg_peek_uint8"); } @@ -482,7 +482,7 @@ apr_status_t ajp_msg_peek_uint8(ajp_msg_t *msg, apr_byte_t *rvalue) apr_status_t ajp_msg_get_uint8(ajp_msg_t *msg, apr_byte_t *rvalue) { - if (msg->pos > msg->len) { + if (msg->pos >= msg->len) { return ajp_log_overflow(msg, "ajp_msg_get_uint8"); } @@ -507,7 +507,12 @@ apr_status_t ajp_msg_get_string(ajp_msg_t *msg, const char **rvalue) status = ajp_msg_get_uint16(msg, &size); start = msg->pos; - if ((status != APR_SUCCESS) || (size + start > msg->max_size)) { + if ((status != APR_SUCCESS) || (size + start >= msg->len)) { + return ajp_log_overflow(msg, "ajp_msg_get_string"); + } + + /* Verify that the expected null terminator is actually present */ + if (msg->buf[start + size] != '\0') { return ajp_log_overflow(msg, "ajp_msg_get_string"); } diff --git a/modules/proxy/mod_proxy_fcgi.c b/modules/proxy/mod_proxy_fcgi.c index d5a52596969..af3fb896bc0 100644 --- a/modules/proxy/mod_proxy_fcgi.c +++ b/modules/proxy/mod_proxy_fcgi.c @@ -1342,9 +1342,15 @@ static const char *cmd_setenv(cmd_parms *cmd, void *in_dconf, const char *err; sei_entry *new; const char *envvar = arg2; + unsigned int flags = 0; + + /* Use restricted ap_expr() parser in htaccess context. */ + if (cmd->pool == cmd->temp_pool) { + flags |= AP_EXPR_FLAG_RESTRICTED; + } new = apr_array_push(dconf->env_fixups); - new->cond = ap_expr_parse_cmd(cmd, arg1, 0, &err, NULL); + new->cond = ap_expr_parse_cmd(cmd, arg1, flags, &err, NULL); if (err) { return apr_psprintf(cmd->pool, "Could not parse expression \"%s\": %s", arg1, err); @@ -1371,7 +1377,8 @@ static const char *cmd_setenv(cmd_parms *cmd, void *in_dconf, arg3 = ""; } - new->subst = ap_expr_parse_cmd(cmd, arg3, AP_EXPR_FLAG_STRING_RESULT, &err, NULL); + flags |= AP_EXPR_FLAG_STRING_RESULT; + new->subst = ap_expr_parse_cmd(cmd, arg3, flags, &err, NULL); if (err) { return apr_psprintf(cmd->pool, "Could not parse expression \"%s\": %s", arg3, err); diff --git a/modules/session/mod_session_crypto.c b/modules/session/mod_session_crypto.c index f072d4c6fbc..67b9e75464f 100644 --- a/modules/session/mod_session_crypto.c +++ b/modules/session/mod_session_crypto.c @@ -69,8 +69,6 @@ typedef struct { #define AP_SIPHASH_KSIZE APR_SIPHASH_KSIZE #define ap_siphash24_auth apr_siphash24_auth -#define ap_crypto_equals apr_crypto_equals - #else #define AP_SIPHASH_DSIZE 8 @@ -165,21 +163,6 @@ static void ap_siphash24_auth(unsigned char out[AP_SIPHASH_DSIZE], U64TO8_LE(out, h); } -static int ap_crypto_equals(const void *buf1, const void *buf2, - apr_size_t size) -{ - const unsigned char *p1 = buf1; - const unsigned char *p2 = buf2; - unsigned char diff = 0; - apr_size_t i; - - for (i = 0; i < size; ++i) { - diff |= p1[i] ^ p2[i]; - } - - return 1 & ((diff - 1) >> 8); -} - #endif static void compute_auth(const void *src, apr_size_t len, @@ -404,7 +387,7 @@ static apr_status_t decrypt_string(request_rec * r, const apr_crypto_t *f, * the MAC and comparing it (timing safe) with the one in the payload. */ compute_auth(slider, len, passphrase, passlen, auth); - if (!ap_crypto_equals(auth, decoded, AP_SIPHASH_DSIZE)) { + if (!ap_memeq_timingsafe(auth, decoded, AP_SIPHASH_DSIZE)) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, res, r, APLOGNO(10006) "auth does not match, skipping"); continue; diff --git a/server/util.c b/server/util.c index eda0eceaf9c..d1d06fc15b4 100644 --- a/server/util.c +++ b/server/util.c @@ -3934,3 +3934,141 @@ AP_DECLARE(const char *)ap_dir_fnmatch(ap_dir_match_t *w, const char *path, return NULL; } + + +#if APR_VERSION_AT_LEAST(1,8,0) +AP_DECLARE(int) ap_memeq_timingsafe(const void *buf1, const void *buf2, + apr_size_t n) +{ + return apr_memeq_timingsafe(buf1, buf2, n); +} + +AP_DECLARE(int) ap_streq_timingsafe(const char *sec1, const char *str2) +{ + return apr_streq_timingsafe(sec1, str2); +} + +AP_DECLARE(int) ap_strneq_timingsafe(const char *sec1, const char *str2, + apr_size_t n) +{ + return apr_strneq_timingsafe(sec1, str2, n); +} + +#else /* !APR_VERSION_AT_LEAST(1,8,0) */ + +/* A volatile variable which is always zero but allows to block the compiler + * from optimizing or eliding code using it. Volatile forces the compiler to + * emit a memory load for which no value can be assumed, so for instance an + * add/sub/xor/or with "optblocker" is a noop that will hide the result to + * the optimizer. + */ +static volatile const apr_uint32_t optblocker; + +/* Return whether x is not zero, with no branching controlled by x. + * + * Taken from the cryptoint library (public domain) by D. J. Bernstein, + * which provides timing attacks safe integer operations/primitives. + * Code: + * https://lib.mceliece.org/libmceliece-20250507/cryptoint/crypto_uint32.h + * Paper: + * https://cr.yp.to/papers/cryptoint-20250424.pdf + */ +#if __has_attribute(always_inline) +__attribute__((always_inline)) +#endif +static APR_INLINE int test_nonzero_timingsafe(apr_uint32_t x) +{ + x |= -x; /* sets the most significant bit unless x == 0 */ + + /* shift bit 31 (MSB) to bit 0 */ + x >>= 32-6; /* keep 6 bits */ + x += optblocker; /* lose the optimizer */ + x >>= 5; /* keep the (original) MSB only */ + + /* x is now 0 or 1 */ + return x & INT_MAX; +} + +AP_DECLARE(int) ap_memeq_timingsafe(const void *buf1, const void *buf2, + apr_size_t n) +{ + apr_uint32_t diff = 0; + volatile apr_size_t count = n; /* prevent loop unrolling */ + apr_size_t i = 0; + + for (; i < count; ++i) { + const unsigned char c1 = ((volatile const unsigned char *)buf1)[i]; + const unsigned char c2 = ((volatile const unsigned char *)buf2)[i]; + + diff |= c1 ^ c2; /* sets diff to non-zero whenever c1 != c2 */ + } + + /* (diff == 0) <=> (diff != 0) ^ 1 */ + return test_nonzero_timingsafe(diff) ^ 1; +} + +AP_DECLARE(int) ap_streq_timingsafe(const char *sec1, const char *str2) +{ + apr_uint32_t diff = 0; + apr_size_t i1 = 0, i2 = 0; + + for (;; ++i2) { + const unsigned char c1 = ((volatile const unsigned char *)sec1)[i1]; + const unsigned char c2 = ((volatile const unsigned char *)str2)[i2]; + + diff |= c1 ^ c2; /* sets diff to non-zero whenever c1 != c2 */ + + /* Not a shortest/longest match because an attacker would usually know + * one of the strings and could then determine the length of the other. + * So assume only sec1 and its length are secret and stop the loop at + * the end of str2. If sec1 is shorter than str2 the loop will continue + * by comparing the rest of str2 with the trailing NUL byte of sec1. + * In any case since the diff above is computed up to and including a + * NUL byte, only the same content and length will raise match. + */ + if (!c2) { + break; + } + + /* Don't go above sec1's NUL byte */ + i1 += test_nonzero_timingsafe(c1); + } + + /* (diff == 0) <=> (diff != 0) ^ 1 */ + return test_nonzero_timingsafe(diff) ^ 1; +} + +AP_DECLARE(int) ap_strneq_timingsafe(const char *sec1, const char *str2, + apr_size_t n) +{ + apr_uint32_t diff = 0; + volatile apr_size_t count = n; /* prevent loop unrolling */ + apr_size_t i1 = 0, i2 = 0; + + for (; i2 < count; ++i2) { + const unsigned char c1 = ((volatile const unsigned char *)sec1)[i1]; + const unsigned char c2 = ((volatile const unsigned char *)str2)[i2]; + + diff |= c1 ^ c2; /* sets diff to non-zero whenever c1 != c2 */ + + /* Not a shortest/longest match because an attacker would usually know + * one of the strings and could then determine the length of the other. + * So assume only sec1 and its length are secret and stop the loop at + * the end of str2. If sec1 is shorter than str2 the loop will continue + * by comparing the rest of str2 with the trailing NUL byte of sec1. + * In any case since the diff above is computed up to and including a + * NUL byte, only the same content and length will raise match. + */ + if (!c2) { + break; + } + + /* Don't go above sec1's NUL byte */ + i1 += test_nonzero_timingsafe(c1); + } + + /* (diff == 0) <=> (diff != 0) ^ 1 */ + return test_nonzero_timingsafe(diff) ^ 1; +} + +#endif /* !APR_VERSION_AT_LEAST(1,8,0) */