Server : Apache System : Linux webd348.cluster026.gra.hosting.ovh.net 5.15.148-ovh-vps-grsec-zfs-classid #1 SMP Thu Feb 8 09:41:04 UTC 2024 x86_64 User : hednacluml ( 122243) PHP Version : 8.3.9 Disable Function : _dyuweyrj4,_dyuweyrj4r,dl Directory : /home/hednacluml/jobs/ecrire/inc/ |
<?php /***************************************************************************\ * SPIP, Système de publication pour l'internet * * * * Copyright © avec tendresse depuis 2001 * * Arnaud Martin, Antoine Pitrou, Philippe Rivière, Emmanuel Saint-James * * * * Ce programme est un logiciel libre distribué sous licence GNU/GPL. * \***************************************************************************/ /** * 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 = 16, $sel = '') { $seed = (int)round(((float)microtime() + 1) * time()); mt_srand($seed); $s = ''; $pass = ''; for ($i = 0; $i < $longueur; $i++) { if (!$s) { $s = random_int(0, mt_getrandmax()); if (!$s) { $s = random_int(0, mt_getrandmax()); } $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); $seeded = true; } $s = random_int(0, mt_getrandmax()); if (!$s) { $s = random_int(0, mt_getrandmax()); } 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( ['nom', 'valeur'], 'spip_meta', sql_in('nom', ['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)) { include_spip('inc/config'); if (!$low_sec = lire_config('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', ['low_sec' => $low_sec], 'id_auteur = ' . intval($id_auteur)); } } return $low_sec; } /** * Vérifie un accès à faible sécurité * * Vérifie qu'un visiteur peut accéder à la page demandée, * qui est protégée par une clé, calculée à partir du low_sec de l'auteur, * et des paramètres le composant l'appel (op, args) * * @param int $id_auteur * L'auteur qui demande la page * @param string $cle * La clé à tester * @param string $dir * Un type d'accès (nom du répertoire dans lequel sont rangés les squelettes demandés, tel que 'rss') * @param string $op * Nom de l'opération éventuelle * @param string $args * Nom de l'argument calculé * @return bool * True si on a le droit d'accès, false sinon. **@example * `[(#ID_AUTEUR|securiser_acces{#ENV{cle}, rss, #ENV{op}, #ENV{args}}|sinon_interdire_acces)]` * * @see generer_url_api_low_sec() pour generer une url api low sec * @see afficher_low_sec() pour calculer une clé valide * @uses verifier_low_sec() * * @filtre */ function securiser_acces_low_sec( $id_auteur, #[\SensitiveParameter] $cle, $dir, $op = '', $args = '' ) { if ($op) { $dir .= " $op $args"; } return verifier_low_sec($id_auteur, $cle, $dir); } /** * Generer une url xxx.api/$id_auteur/$cle/$format/$fond?$args * @param string $script * @param string $format * @param string $fond * @param string $path * @param string $args * @param bool $no_entities * @param bool|null $public * @return string */ function generer_url_api_low_sec(string $script, string $format, string $fond, string $path, string $args, bool $no_entities = false, ?bool $public = null) { $id_auteur = $GLOBALS['visiteur_session']['id_auteur'] ?? 0; $cle = afficher_low_sec($id_auteur, "$script/$format $fond $args"); $path = "$id_auteur/$cle/$format/$fond" . ($path ? "/$path" : ''); return generer_url_api($script, $path, $args, $no_entities, $public); } /** * 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 * @deprecated 4.1 */ function param_low_sec($op, $args = [], $lang = '', $mime = 'rss') { trigger_deprecation('spip', '4.1', 'Using "%s" is deprecated, use "%s" instead', __FUNCTION__, 'generer_url_api_low_sec'); $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, #[\SensitiveParameter] $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', ['low_sec' => ''], 'id_auteur = ' . intval($id_auteur)); } /** * 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 auth_ldap_connect() if (include_spip('auth/ldap') and auth_ldap_connect()) { return; } generer_htpasswd_files($htpasswd, "$htpasswd-admin"); } /** * Generer le fichier de htpasswd contenant les htpass * @param $htpasswd * @param $htpasswd_admin */ function generer_htpasswd_files($htpasswd, $htpasswd_admin) { if ($generer_htpasswd = charger_fonction('generer_htpasswd_files', 'inc', true)) { $generer_htpasswd($htpasswd, $htpasswd_admin); } $pwd_all = ''; // login:htpass pour tous $pwd_admin = ''; // login:htpass pour les admins $res = sql_select('login, htpass, statut', 'spip_auteurs', "htpass!='' AND login!='' AND " . sql_in('statut', ['1comite', '0minirezo', 'nouveau'])); while ($row = sql_fetch($res)) { if (strlen($row['login']) and strlen($row['htpass'])) { $ligne = $row['login'] . ':' . $row['htpass'] . "\n"; $pwd_all .= $ligne; if ($row['statut'] == '0minirezo') { $pwd_admin .= $ligne; } } } if ($pwd_all) { ecrire_fichier($htpasswd, $pwd_all); ecrire_fichier($htpasswd_admin, $pwd_admin); spip_log("Ecriture de $htpasswd et $htpasswd_admin", 'htpass'); } } /** * Créer un password htaccess * * @link http://docs.php.net/manual/fr/function.crypt.php Documentation de `crypt()` * * @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( #[\SensitiveParameter] $pass ) { if ($generer_htpass = charger_fonction('generer_htpass', 'inc', true)) { return $generer_htpass($pass); } return ''; } /** * Installe ou vérifie un fichier .htaccess, y compris sa prise en compte par Apache * * @uses recuperer_url() * @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_url($t, ['methode' => 'HEAD', 'taille_max' => 0, 'follow_location' => false]); $ht = ($ht['status'] ?? null) === 403; } } 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[] = ['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 $GLOBALS['meta']['creer_htaccess'] ?? ''; }