[SPIP][PLUGINS] v3.0-->v3.2
[lhc/web/www.git] / www / ecrire / inc / acces.php
index 90cd3dc..87c19c7 100644 (file)
@@ -3,18 +3,36 @@
 /***************************************************************************\
  *  SPIP, Systeme de publication pour l'internet                           *
  *                                                                         *
- *  Copyright (c) 2001-2016                                                *
+ *  Copyright (c) 2001-2017                                                *
  *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
  *                                                                         *
  *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
  *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
 \***************************************************************************/
 
-if (!defined('_ECRIRE_INC_VERSION')) return;
+/**
+ * Gestion des nombres aléatoires et de certains accès au site
+ *
+ * @package SPIP\Core\Authentification
+ **/
+
+if (!defined('_ECRIRE_INC_VERSION')) {
+       return;
+}
+
+/**
+ * Créer un mot de passe
+ *
+ * @param int $longueur
+ *     Longueur du password créé
+ * @param string $sel
+ *     Clé pour un salage supplémentaire
+ * @return string
+ *     Mot de passe
+ **/
+function creer_pass_aleatoire($longueur = 8, $sel = '') {
+       $seed = (int)round(((float)microtime() + 1) * time());
 
-// http://doc.spip.org/@creer_pass_aleatoire
-function creer_pass_aleatoire($longueur = 8, $sel = "") {
-       $seed = (double) (microtime() + 1) * time();
        mt_srand($seed);
        srand($seed);
        $s = '';
@@ -22,57 +40,101 @@ function creer_pass_aleatoire($longueur = 8, $sel = "") {
        for ($i = 0; $i < $longueur; $i++) {
                if (!$s) {
                        $s = mt_rand();
-                       if (!$s) $s = rand();
-                       $s = substr(md5(uniqid($s).$sel), 0, 16);
+                       if (!$s) {
+                               $s = rand();
+                       }
+                       $s = substr(md5(uniqid($s) . $sel), 0, 16);
                }
-               $r = unpack("Cr", pack("H2", $s.$s));
+               $r = unpack('Cr', pack('H2', $s . $s));
                $x = $r['r'] & 63;
-               if ($x < 10) $x = chr($x + 48);
-               else if ($x < 36) $x = chr($x + 55);
-               else if ($x < 62) $x = chr($x + 61);
-               else if ($x == 63) $x = '/';
-               else $x = '.';
+               if ($x < 10) {
+                       $x = chr($x + 48);
+               } else {
+                       if ($x < 36) {
+                               $x = chr($x + 55);
+                       } else {
+                               if ($x < 62) {
+                                       $x = chr($x + 61);
+                               } else {
+                                       if ($x == 63) {
+                                               $x = '/';
+                                       } else {
+                                               $x = '.';
+                                       }
+                               }
+                       }
+               }
                $pass .= $x;
                $s = substr($s, 2);
        }
-       $pass = preg_replace("@[./]@", "a", $pass);
-       $pass = preg_replace("@[I1l]@", "L", $pass);
-       $pass = preg_replace("@[0O]@", "o", $pass);
+       $pass = preg_replace('@[./]@', 'a', $pass);
+       $pass = preg_replace('@[I1l]@', 'L', $pass);
+       $pass = preg_replace('@[0O]@', 'o', $pass);
+
        return $pass;
 }
 
 /**
- * Creer un identifiant aleatoire
- *
- * http://doc.spip.org/@creer_uniqid
+ * Créer un identifiant aléatoire
  *
- * @return string
+ * @return string Identifiant
  */
 function creer_uniqid() {
        static $seeded;
 
        if (!$seeded) {
-               $seed = (double) (microtime() + 1) * time();
+               $seed = (int)round(((float)microtime() + 1) * time());
                mt_srand($seed);
                srand($seed);
                $seeded = true;
        }
 
        $s = mt_rand();
-       if (!$s) $s = rand();
+       if (!$s) {
+               $s = rand();
+       }
+
        return uniqid($s, 1);
 }
 
-//
-// Renouvellement de l'alea utilise pour securiser les scripts dans action/
-//
-
-// http://doc.spip.org/@renouvelle_alea
-function renouvelle_alea() {
-       if (!isset($GLOBALS['meta']['alea_ephemere'])){
+/**
+ * Charge les aléas ehpémères s'il ne sont pas encore dans la globale
+ *
+ * Si les métas 'alea_ephemere' et 'alea_ephemere_ancien' se sont pas encore chargées
+ * en méta (car elles ne sont pas stockées, pour sécurité, dans le fichier cache des métas),
+ * alors on les récupère en base. Et on les ajoute à nos métas globales.
+ *
+ * @see touch_meta()
+ * @return string Retourne l'alea éphemère actuel au passage
+ */
+function charger_aleas() {
+       if (!isset($GLOBALS['meta']['alea_ephemere'])) {
                include_spip('base/abstract_sql');
-               $GLOBALS['meta']['alea_ephemere'] = sql_getfetsel('valeur', 'spip_meta', "nom='alea_ephemere'");
+               $aleas = sql_allfetsel(
+                       array('nom', 'valeur'),
+                       'spip_meta',
+                       sql_in("nom", array('alea_ephemere', 'alea_ephemere_ancien')),
+                       '', '', '', '', '',
+                       'continue'
+               );
+               if ($aleas) {
+                       foreach ($aleas as $a) {
+                               $GLOBALS['meta'][$a['nom']] = $a['valeur'];
+                       }
+                       return $GLOBALS['meta']['alea_ephemere'];
+               } else {
+                       spip_log("aleas indisponibles", "session");
+                       return "";
+               }
        }
+       return $GLOBALS['meta']['alea_ephemere'];
+}
+
+/**
+ * Renouveller l'alea (utilisé pour sécuriser les scripts du répertoire `action/`)
+ **/
+function renouvelle_alea() {
+       charger_aleas();
        ecrire_meta('alea_ephemere_ancien', @$GLOBALS['meta']['alea_ephemere'], 'non');
        $GLOBALS['meta']['alea_ephemere'] = md5(creer_uniqid());
        ecrire_meta('alea_ephemere', $GLOBALS['meta']['alea_ephemere'], 'non');
@@ -80,79 +142,148 @@ function renouvelle_alea() {
        spip_log("renouvellement de l'alea_ephemere");
 }
 
-//
-// low-security : un ensemble de fonctions pour gerer de l'identification
-// faible via les URLs (suivi RSS, iCal...)
-//
-// http://doc.spip.org/@low_sec
+
+/**
+ * Retourne une clé de sécurité faible (low_sec) pour l'auteur indiqué
+ *
+ * low-security est un ensemble de fonctions pour gérer de l'identification
+ * faible via les URLs (suivi RSS, iCal...)
+ *
+ * Retourne la clé de sécurité low_sec de l'auteur (la génère si elle n'exite pas)
+ * ou la clé de sécurité low_sec du site (si auteur invalide)(la génère si elle
+ * n'existe pas).
+ *
+ * @param int $id_auteur
+ *     Identifiant de l'auteur
+ * @return string
+ *     Clé de sécurité.
+ **/
 function low_sec($id_auteur) {
        // Pas d'id_auteur : low_sec
        if (!$id_auteur = intval($id_auteur)) {
                if (!$low_sec = $GLOBALS['meta']['low_sec']) {
                        ecrire_meta('low_sec', $low_sec = creer_pass_aleatoire());
                }
-       }
-       else {
-               $low_sec = sql_getfetsel("low_sec", "spip_auteurs", "id_auteur = $id_auteur");
+       } else {
+               $low_sec = sql_getfetsel('low_sec', 'spip_auteurs', 'id_auteur = '.intval($id_auteur));
                if (!$low_sec) {
                        $low_sec = creer_pass_aleatoire();
-                       sql_updateq("spip_auteurs", array("low_sec" => $low_sec), "id_auteur = $id_auteur");
+                       sql_updateq('spip_auteurs', array('low_sec' => $low_sec), 'id_auteur = '.intval($id_auteur));
                }
        }
+
        return $low_sec;
 }
 
-// Inclure les arguments significatifs pour le hachage
-// cas particulier du statut pour compatibilite ancien rss/suivi_revisions
-
-function param_low_sec($op, $args=array(), $lang='', $mime='rss')
-{
+/**
+ * Inclure les arguments significatifs pour le hachage
+ *
+ * Cas particulier du statut pour compatibilité ancien rss/suivi_revisions
+ *
+ * @param string $op
+ * @param array $args
+ * @param string $lang
+ * @param string $mime
+ *     Par défaut 'rss'.
+ * @return string
+ */
+function param_low_sec($op, $args = array(), $lang = '', $mime = 'rss') {
        $a = $b = '';
-       foreach ($args as $val => $var)
+       foreach ($args as $val => $var) {
                if ($var) {
-                       if ($val<>'statut') $a .= ':' . $val.'-'.$var;
-                       $b .= $val.'='.$var . '&';
+                       if ($val <> 'statut') {
+                               $a .= ':' . $val . '-' . $var;
+                       }
+                       $b .= $val . '=' . $var . '&';
                }
-       $a = substr($a,1);
+       }
+       $a = substr($a, 1);
        $id = intval(@$GLOBALS['connect_id_auteur']);
+
        return $b
-         . "op="
-         . $op
-         . "&id="
-         . $id
-         . "&cle="
-         . afficher_low_sec($id, "$mime $op $a")
-         . (!$a ? '' : "&args=$a")
-         . (!$lang ? '' : "&lang=$lang");
+       . 'op='
+       . $op
+       . '&id='
+       . $id
+       . '&cle='
+       . afficher_low_sec($id, "$mime $op $a")
+       . (!$a ? '' : "&args=$a")
+       . (!$lang ? '' : "&lang=$lang");
 }
 
-// http://doc.spip.org/@afficher_low_sec
-function afficher_low_sec ($id_auteur, $action='') {
-       return substr(md5($action.low_sec($id_auteur)),0,8);
+/**
+ * Retourne une clé basée sur le low_sec de l'auteur et l'action demandé
+ *
+ * @uses low_sec()
+ *
+ * @param int $id_auteur
+ *     Identifiant de l'auteur
+ * @param string $action
+ *     Action désirée
+ * @return string
+ *     Clé
+ **/
+function afficher_low_sec($id_auteur, $action = '') {
+       return substr(md5($action . low_sec($id_auteur)), 0, 8);
 }
 
-// http://doc.spip.org/@verifier_low_sec
-function verifier_low_sec ($id_auteur, $cle, $action='') {
+/**
+ * Vérifie une clé basée sur le low_sec de l'auteur et l'action demandé
+ *
+ * @uses afficher_low_sec()
+ *
+ * @param int $id_auteur
+ *     Identifiant de l'auteur
+ * @param string $cle
+ *     Clé à comparer
+ * @param string $action
+ *     Action désirée
+ * @return bool
+ *     true si les clés corresponde, false sinon
+ **/
+function verifier_low_sec($id_auteur, $cle, $action = '') {
        return ($cle == afficher_low_sec($id_auteur, $action));
 }
 
-// http://doc.spip.org/@effacer_low_sec
+/**
+ * Efface la clé de sécurité faible (low_sec) d'un auteur
+ *
+ * @param int $id_auteur
+ *     Identifiant de l'auteur
+ **/
 function effacer_low_sec($id_auteur) {
-       if (!$id_auteur = intval($id_auteur)) return; // jamais trop prudent ;)
-       sql_updateq("spip_auteurs", array("low_sec" => ''), "id_auteur = $id_auteur");
+       if (!$id_auteur = intval($id_auteur)) {
+               return;
+       } // jamais trop prudent ;)
+       sql_updateq('spip_auteurs', array('low_sec' => ''), 'id_auteur = '.intval($id_auteur));
 }
 
-// http://doc.spip.org/@initialiser_sel
+/**
+ * Initialiser la globale htsalt si cela n'a pas déjà été fait.
+ *
+ * @return void|bool
+ */
 function initialiser_sel() {
-       global $htsalt;
-       if (CRYPT_MD5) $htsalt = '$1$'.creer_pass_aleatoire();
-       else return "";
+       if (CRYPT_MD5) {
+               $GLOBALS['htsalt'] = '$1$' . creer_pass_aleatoire();
+       } else {
+               return '';
+       }
 }
 
-// Cette fonction ne sert qu'a la connexion en mode http_auth.non LDAP
-// Son role est de creer le fichier htpasswd
-// Voir le plugin "acces restreint"
-// http://doc.spip.org/@ecrire_acces
+/**
+ * Créer un fichier htpasswd
+ *
+ * Cette fonction ne sert qu'à la connexion en mode http_auth.non LDAP.
+ * Voir le plugin «Accès Restreint»
+ *
+ * S'appuie sur la meta `creer_htpasswd` pour savoir s'il faut créer
+ * le `.htpasswd`.
+ *
+ * @return null|void
+ *     - null si pas de htpasswd à créer, ou si LDAP
+ *     - void sinon.
+ **/
 function ecrire_acces() {
        $htaccess = _DIR_RESTREINT . _ACCESS_FILE_NAME;
        $htpasswd = _DIR_TMP . _AUTH_USER_FILE;
@@ -160,10 +291,12 @@ function ecrire_acces() {
        // Cette variable de configuration peut etre posee par un plugin
        // par exemple acces_restreint ;
        // si .htaccess existe, outrepasser spip_meta
-       if (($GLOBALS['meta']['creer_htpasswd'] != 'oui')
-       AND !@file_exists($htaccess)) {
+       if ((!isset($GLOBALS['meta']['creer_htpasswd'])
+                       or ($GLOBALS['meta']['creer_htpasswd'] != 'oui'))
+               and !@file_exists($htaccess)
+       ) {
                spip_unlink($htpasswd);
-               spip_unlink($htpasswd."-admin");
+               spip_unlink($htpasswd . '-admin');
                return;
        }
 
@@ -172,79 +305,130 @@ function ecrire_acces() {
        // attention, il faut au prealable se connecter a la base (necessaire car utilise par install)
        // TODO: factoriser avec auth/spip qui fait deja ce job et generaliser le test spip_connect_ldap()
 
-       if (spip_connect_ldap()) return;
+       if (spip_connect_ldap()) {
+               return;
+       }
        $p1 = ''; // login:htpass pour tous
        $p2 = ''; // login:htpass pour les admins
-       $s = sql_select("login, htpass, statut", "spip_auteurs", sql_in("statut",  array('1comite','0minirezo','nouveau')));
+       $s = sql_select('login, htpass, statut', 'spip_auteurs', sql_in('statut', array('1comite', '0minirezo', 'nouveau')));
        while ($t = sql_fetch($s)) {
-               if (strlen($t['login']) AND strlen($t['htpass'])) {
-                       $p1 .= $t['login'].':'.$t['htpass']."\n";
-                       if ($t['statut'] == '0minirezo')
-                               $p2 .= $t['login'].':'.$t['htpass']."\n";
+               if (strlen($t['login']) and strlen($t['htpass'])) {
+                       $p1 .= $t['login'] . ':' . $t['htpass'] . "\n";
+                       if ($t['statut'] == '0minirezo') {
+                               $p2 .= $t['login'] . ':' . $t['htpass'] . "\n";
+                       }
                }
        }
        if ($p1) {
-         ecrire_fichier($htpasswd, $p1);
-         ecrire_fichier($htpasswd.'-admin', $p2);
-         spip_log("Ecriture de $htpasswd et $htpasswd-admin");
+               ecrire_fichier($htpasswd, $p1);
+               ecrire_fichier($htpasswd . '-admin', $p2);
+               spip_log("Ecriture de $htpasswd et $htpasswd-admin");
        }
 }
 
-
-// http://doc.spip.org/@generer_htpass
+/**
+ * Créer un password htaccess
+ *
+ * @link http://docs.php.net/manual/fr/function.crypt.php Documentation de `crypt()`
+ *
+ * @global string $htsalt
+ *   Une chaîne de sel sur laquelle sera fondée le hachage.
+ * @param string $pass
+ *   Le mot de passe
+ * @return void|string
+ *  La chaîne hachée si fonction crypt présente, rien sinon.
+ */
 function generer_htpass($pass) {
-       global $htsalt;
-       if (function_exists('crypt'))
-               return crypt($pass, $htsalt);
+       if (function_exists('crypt')) {
+               return crypt($pass, $GLOBALS['htsalt']);
+       }
 }
 
-//
-// Installe ou verifie un .htaccess, y compris sa prise en compte par Apache
-//
-// http://doc.spip.org/@verifier_htaccess
-function verifier_htaccess($rep, $force=false) {
-       $htaccess = rtrim($rep,"/") . "/" . _ACCESS_FILE_NAME;
-       if (((@file_exists($htaccess)) OR defined('_TEST_DIRS')) AND !$force)
+/**
+ * Installe ou vérifie un fichier .htaccess, y compris sa prise en compte par Apache
+ *
+ * @uses recuperer_lapage()
+ * @param string $rep
+ *     Nom du répertoire où SPIP doit vérifier l'existence d'un fichier .htaccess
+ * @param bool $force
+ * @return boolean
+ */
+function verifier_htaccess($rep, $force = false) {
+       $htaccess = rtrim($rep, '/') . '/' . _ACCESS_FILE_NAME;
+       if (((@file_exists($htaccess)) or defined('_TEST_DIRS')) and !$force) {
                return true;
-       if ($ht = @fopen($htaccess, "w")) {
-               fputs($ht, "deny from all\n");
+       }
+
+       // directive deny compatible Apache 2.0+
+       $deny =
+               '# Deny all requests from Apache 2.4+.
+<IfModule mod_authz_core.c>
+  Require all denied
+</IfModule>
+# Deny all requests from Apache 2.0-2.2.
+<IfModule !mod_authz_core.c>
+  Deny from all
+</IfModule>
+';
+       // support des vieilles versions Apache 1.x mais uniquement si elles l'annoncent (pas en mode PROD)
+       if (function_exists('apache_get_version')
+               and $v = apache_get_version()
+               and strncmp($v, 'Apache/1.', 9) == 0) {
+               $deny = "deny from all\n";
+       }
+
+       if ($ht = @fopen($htaccess, 'w')) {
+               fputs($ht, $deny);
                fclose($ht);
                @chmod($htaccess, _SPIP_CHMOD & 0666);
-               $t = rtrim($rep,"/") . "/.ok";
-               if ($ht = @fopen($t, "w")) {
+               $t = rtrim($rep, '/') . '/.ok';
+               if ($ht = @fopen($t, 'w')) {
                        @fclose($ht);
                        include_spip('inc/distant');
-                       $t = substr($t,strlen(_DIR_RACINE));
+                       $t = substr($t, strlen(_DIR_RACINE));
                        $t = url_de_base() . $t;
                        $ht = recuperer_lapage($t, false, 'HEAD', 0);
                        // htaccess inoperant si on a recupere des entetes HTTP
                        // (ignorer la reussite si connexion par fopen)
-                       $ht = !(isset($ht[0]) AND $ht[0]);
+                       $ht = !(isset($ht[0]) and $ht[0]);
                }
        }
-       spip_log("Creation de $htaccess " . ($ht ? " reussie" : " manquee"));
-       return $ht;
-}      
-
+       spip_log("Creation de $htaccess " . ($ht ? ' reussie' : ' manquee'));
 
+       return $ht;
+}
 
-// http://doc.spip.org/@gerer_htaccess
+/**
+ * Créer un fichier .htaccess pour chaque répertoire d'extension
+ * dans `_DIR_IMG` si la configuration le demande
+ *
+ * @note
+ *     La variable de configuration `creer_htaccess` peut être posée
+ *     par un plugin tel acces_restreint.
+ *
+ * @uses _DIR_IMG
+ * @uses verifier_htaccess()
+ *
+ * @return string
+ *         Valeur de la configuration `creer_htaccess`
+ */
 function gerer_htaccess() {
        // Cette variable de configuration peut etre posee par un plugin
        // par exemple acces_restreint
-       $f = ($GLOBALS['meta']['creer_htaccess'] === 'oui');
+       $f = isset($GLOBALS['meta']['creer_htaccess']) and ($GLOBALS['meta']['creer_htaccess'] === 'oui');
        $dirs = sql_allfetsel('extension', 'spip_types_documents');
        $dirs[] = array('extension' => 'distant');
-       foreach($dirs as $e) {
+       foreach ($dirs as $e) {
                if (is_dir($dir = _DIR_IMG . $e['extension'])) {
-                       if ($f)
+                       if ($f) {
                                verifier_htaccess($dir);
-                       else spip_unlink($dir . '/' . _ACCESS_FILE_NAME);
+                       } else {
+                               spip_unlink($dir . '/' . _ACCESS_FILE_NAME);
+                       }
                }
        }
-       return $GLOBALS['meta']['creer_htaccess'];
+
+       return isset($GLOBALS['meta']['creer_htaccess']) ? $GLOBALS['meta']['creer_htaccess'] : '';
 }
 
 initialiser_sel();
-
-?>