/ecrire/inc/acces.php
PHP | 434 lines | 251 code | 31 blank | 152 comment | 45 complexity | 23fd6d202f449b7e0e703c17475fe9fe MD5 | raw file
Possible License(s): LGPL-2.1, MIT
- <?php
- /***************************************************************************\
- * SPIP, Systeme de publication pour l'internet *
- * *
- * 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. *
- \***************************************************************************/
- /**
- * 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());
- mt_srand($seed);
- srand($seed);
- $s = '';
- $pass = '';
- for ($i = 0; $i < $longueur; $i++) {
- if (!$s) {
- $s = mt_rand();
- if (!$s) {
- $s = rand();
- }
- $s = substr(md5(uniqid($s) . $sel), 0, 16);
- }
- $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 = '.';
- }
- }
- }
- }
- $pass .= $x;
- $s = substr($s, 2);
- }
- $pass = preg_replace('@[./]@', 'a', $pass);
- $pass = preg_replace('@[I1l]@', 'L', $pass);
- $pass = preg_replace('@[0O]@', 'o', $pass);
- return $pass;
- }
- /**
- * Créer un identifiant aléatoire
- *
- * @return string Identifiant
- */
- function creer_uniqid() {
- static $seeded;
- if (!$seeded) {
- $seed = (int)round(((float)microtime() + 1) * time());
- mt_srand($seed);
- srand($seed);
- $seeded = true;
- }
- $s = mt_rand();
- if (!$s) {
- $s = rand();
- }
- return uniqid($s, 1);
- }
- /**
- * 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');
- $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');
- ecrire_meta('alea_ephemere_date', time(), 'non');
- spip_log("renouvellement de l'alea_ephemere");
- }
- /**
- * 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 = '.intval($id_auteur));
- if (!$low_sec) {
- $low_sec = creer_pass_aleatoire();
- 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 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) {
- if ($var) {
- if ($val <> 'statut') {
- $a .= ':' . $val . '-' . $var;
- }
- $b .= $val . '=' . $var . '&';
- }
- }
- $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");
- }
- /**
- * 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);
- }
- /**
- * 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));
- }
- /**
- * 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 = '.intval($id_auteur));
- }
- /**
- * Initialiser la globale htsalt si cela n'a pas déjà été fait.
- *
- * @return void|bool
- */
- function initialiser_sel() {
- if (CRYPT_MD5) {
- $GLOBALS['htsalt'] = '$1$' . creer_pass_aleatoire();
- } else {
- return '';
- }
- }
- /**
- * 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;
- // Cette variable de configuration peut etre posee par un plugin
- // par exemple acces_restreint ;
- // si .htaccess existe, outrepasser spip_meta
- if ((!isset($GLOBALS['meta']['creer_htpasswd'])
- or ($GLOBALS['meta']['creer_htpasswd'] != 'oui'))
- and !@file_exists($htaccess)
- ) {
- spip_unlink($htpasswd);
- spip_unlink($htpasswd . '-admin');
- return;
- }
- # remarque : ici on laisse passer les "nouveau" de maniere a leur permettre
- # de devenir redacteur le cas echeant (auth http)... a nettoyer
- // 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;
- }
- $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')));
- 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 ($p1) {
- ecrire_fichier($htpasswd, $p1);
- ecrire_fichier($htpasswd . '-admin', $p2);
- spip_log("Ecriture de $htpasswd et $htpasswd-admin");
- }
- }
- /**
- * 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) {
- if (function_exists('crypt')) {
- return crypt($pass, $GLOBALS['htsalt']);
- }
- }
- /**
- * 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;
- }
- // 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')) {
- @fclose($ht);
- include_spip('inc/distant');
- $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]);
- }
- }
- spip_log("Creation de $htaccess " . ($ht ? ' reussie' : ' manquee'));
- return $ht;
- }
- /**
- * 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 = 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) {
- if (is_dir($dir = _DIR_IMG . $e['extension'])) {
- if ($f) {
- verifier_htaccess($dir);
- } else {
- spip_unlink($dir . '/' . _ACCESS_FILE_NAME);
- }
- }
- }
- return isset($GLOBALS['meta']['creer_htaccess']) ? $GLOBALS['meta']['creer_htaccess'] : '';
- }
- initialiser_sel();