[SPIP] ~v3.0.20-->v3.0.25
[lhc/web/clavette_www.git] / www / ecrire / inc / securiser_action.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2016 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
8 * *
9 * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
10 * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
11 \***************************************************************************/
12
13 if (!defined('_ECRIRE_INC_VERSION')) return;
14
15 /**
16 * interface d'appel:
17 * - au moins un argument: retourne une URL ou un formulaire securises
18 * - sans argument: verifie la securite et retourne _request('arg'), ou exit.
19 *
20 * http://doc.spip.org/@inc_securiser_action_dist
21 *
22 * @param string $action
23 * @param string $arg
24 * @param string $redirect
25 * @param bool|int|string $mode
26 * -1 : renvoyer action, arg et hash sous forme de array()
27 * true ou false : renvoyer une url, avec &amp; (false) ou & (true)
28 * string : renvoyer un formulaire
29 * @param string|int $att
30 * id_auteur pour lequel generer l'action en mode url ou array()
31 * atributs du formulaire en mode formulaire
32 * @param bool $public
33 * @return array|string
34 */
35 function inc_securiser_action_dist($action='', $arg='', $redirect="", $mode=false, $att='', $public=false)
36 {
37 if ($action)
38 return securiser_action_auteur($action, $arg, $redirect, $mode, $att, $public);
39 else {
40 $arg = _request('arg');
41 $hash = _request('hash');
42 $action = _request('action')?_request('action'):_request('formulaire_action');
43 if ($a = verifier_action_auteur("$action-$arg", $hash))
44 return $arg;
45 include_spip('inc/minipres');
46 echo minipres();
47 exit;
48 }
49 }
50
51 /**
52 * Attention: PHP applique urldecode sur $_GET mais pas sur $_POST
53 * cf http://fr.php.net/urldecode#48481
54 * http://doc.spip.org/@securiser_action_auteur
55 *
56 * @param string $action
57 * @param string $arg
58 * @param string $redirect
59 * @param bool|int|string $mode
60 * -1 : renvoyer action, arg et hash sous forme de array()
61 * true ou false : renvoyer une url, avec &amp; (false) ou & (true)
62 * string : renvoyer un formulaire
63 * @param string|int $att
64 * id_auteur pour lequel generer l'action en mode url ou array()
65 * atributs du formulaire en mode formulaire
66 * @param bool $public
67 * @return array|string
68 */
69 function securiser_action_auteur($action, $arg, $redirect="", $mode=false, $att='', $public=false) {
70
71 // mode URL ou array
72 if (!is_string($mode)){
73 $hash = calculer_action_auteur("$action-$arg",is_numeric($att)?$att:null);
74
75 $r = rawurlencode($redirect);
76 if ($mode===-1)
77 return array('action'=>$action,'arg'=>$arg,'hash'=>$hash);
78 else
79 return generer_url_action($action, "arg=$arg&hash=$hash" . (!$r ? '' : "&redirect=$r"), $mode, $public);
80 }
81
82 // mode formulaire
83 $hash = calculer_action_auteur("$action-$arg");
84 $att .= " style='margin: 0px; border: 0px'";
85 if ($redirect)
86 $redirect = "\n\t\t<input name='redirect' type='hidden' value='". str_replace("'", '&#39;', $redirect) ."' />";
87 $mode .= $redirect . "
88 <input name='hash' type='hidden' value='$hash' />
89 <input name='arg' type='hidden' value='$arg' />";
90
91 return generer_form_action($action, $mode, $att, $public);
92 }
93
94 /**
95 * Caracteriser un auteur : l'auteur loge si $id_auteur=null
96 *
97 * http://doc.spip.org/@caracteriser_auteur
98 *
99 * @param int|null $id_auteur
100 * @return array
101 */
102 function caracteriser_auteur($id_auteur=null) {
103 static $caracterisation = array();
104
105 if (is_null($id_auteur) AND !isset($GLOBALS['visiteur_session']['id_auteur'])) {
106 // si l'auteur courant n'est pas connu alors qu'il peut demander une action
107 // c'est une connexion par php_auth ou 1 instal, on se rabat sur le cookie.
108 // S'il n'avait pas le droit de realiser cette action, le hash sera faux.
109 if (isset($_COOKIE['spip_session'])
110 AND (preg_match('/^(\d+)/',$_COOKIE['spip_session'],$r))) {
111 return array($r[1], '');
112 // Necessaire aux forums anonymes.
113 // Pour le reste, ca echouera.
114 } else return array('0','');
115 }
116 // Eviter l'acces SQL si le pass est connu de PHP
117 if (is_null($id_auteur)){
118 $id_auteur = isset($GLOBALS['visiteur_session']['id_auteur'])?$GLOBALS['visiteur_session']['id_auteur']:0;
119 if (isset($GLOBALS['visiteur_session']['pass']) AND $GLOBALS['visiteur_session']['pass'])
120 return $caracterisation[$id_auteur] = array($id_auteur, $GLOBALS['visiteur_session']['pass']);
121 }
122
123 if (isset($caracterisation[$id_auteur])) return $caracterisation[$id_auteur];
124
125 if ($id_auteur) {
126 include_spip('base/abstract_sql');
127 $t = sql_fetsel("id_auteur, pass", "spip_auteurs", "id_auteur=$id_auteur");
128 if ($t)
129 return $caracterisation[$id_auteur] = array($t['id_auteur'], $t['pass']);
130 include_spip('inc/minipres');
131 echo minipres();
132 exit;
133 }
134 // Visiteur anonyme, pour ls forums par exemple
135 else {
136 return array('0','');
137 }
138 }
139
140 /**
141 * Calcule une cle securisee pour une action et un auteur donnes
142 * utilisee pour generer des urls personelles pour executer une action qui modifie la base
143 * et verifier la legitimite de l'appel a l'action
144 *
145 * http://doc.spip.org/@_action_auteur
146 *
147 * @param string $action
148 * @param int $id_auteur
149 * @param string $pass
150 * @param string $alea
151 * @return string
152 */
153 function _action_auteur($action, $id_auteur, $pass, $alea) {
154 static $sha = array();
155 if (!isset($sha[$id_auteur.$pass.$alea])){
156 if (!isset($GLOBALS['meta'][$alea]) AND _request('exec')!=='install') {
157 include_spip('base/abstract_sql');
158 $GLOBALS['meta'][$alea] = sql_getfetsel('valeur', 'spip_meta', "nom=" . sql_quote($alea));
159 if (!($GLOBALS['meta'][$alea])) {
160 include_spip('inc/minipres');
161 echo minipres();
162 spip_log("$alea indisponible");
163 exit;
164 }
165 }
166 include_spip('auth/sha256.inc');
167 $sha[$id_auteur.$pass.$alea] = _nano_sha256($id_auteur.$pass.@$GLOBALS['meta'][$alea]);
168 }
169 if (function_exists('sha1'))
170 return sha1($action.$sha[$id_auteur.$pass.$alea]);
171 else
172 return md5($action.$sha[$id_auteur.$pass.$alea]);
173 }
174
175 /**
176 * Calculer le hash qui signe une action pour un auteur
177 * http://doc.spip.org/@calculer_action_auteur
178 *
179 * @param string $action
180 * @param int|null $id_auteur
181 * @return string
182 */
183 function calculer_action_auteur($action, $id_auteur=null) {
184 list($id_auteur, $pass) = caracteriser_auteur($id_auteur);
185 return _action_auteur($action, $id_auteur, $pass, 'alea_ephemere');
186 }
187
188
189 /**
190 * Verifier le hash de signature d'une action
191 * toujours exclusivement pour l'auteur en cours
192 * http://doc.spip.org/@verifier_action_auteur
193 *
194 * @param $action
195 * @param $hash
196 * @return bool
197 */
198 function verifier_action_auteur($action, $hash) {
199 list($id_auteur, $pass) = caracteriser_auteur();
200 if ($hash == _action_auteur($action, $id_auteur, $pass, 'alea_ephemere'))
201 return true;
202 if ($hash == _action_auteur($action, $id_auteur, $pass, 'alea_ephemere_ancien'))
203 return true;
204 return false;
205 }
206
207 //
208 // Des fonctions independantes du visiteur, qui permettent de controler
209 // par exemple que l'URL d'un document a la bonne cle de lecture
210 //
211
212 /**
213 * Renvoyer le secret du site, et le generer si il n'existe pas encore
214 * Le secret du site doit rester aussi secret que possible, et est eternel
215 * On ne doit pas l'exporter
216 *
217 * http://doc.spip.org/@secret_du_site
218 *
219 * @return string
220 */
221 function secret_du_site() {
222 if (!isset($GLOBALS['meta']['secret_du_site'])){
223 include_spip('base/abstract_sql');
224 $GLOBALS['meta']['secret_du_site'] = sql_getfetsel('valeur', 'spip_meta', "nom='secret_du_site'");
225 }
226 if (!isset($GLOBALS['meta']['secret_du_site'])
227 OR (strlen($GLOBALS['meta']['secret_du_site'])<64)) {
228 include_spip('inc/acces');
229 include_spip('auth/sha256.inc');
230 ecrire_meta('secret_du_site', _nano_sha256($_SERVER["DOCUMENT_ROOT"] . $_SERVER["SERVER_SIGNATURE"] . creer_uniqid()), 'non');
231 lire_metas(); // au cas ou ecrire_meta() ne fonctionne pas
232 }
233 return $GLOBALS['meta']['secret_du_site'];
234 }
235
236 /**
237 * Calculer une signature valable pour une action et pour le site
238 * http://doc.spip.org/@calculer_cle_action
239 *
240 * @param string $action
241 * @return string
242 */
243 function calculer_cle_action($action) {
244 if (function_exists('sha1'))
245 return sha1($action . secret_du_site());
246 else
247 return md5($action . secret_du_site());
248 }
249
250 /**
251 * Verifier la cle de signature d'une action valable pour le site
252 * http://doc.spip.org/@verifier_cle_action
253 *
254 * @param string $action
255 * @param string $cle
256 * @return bool
257 */
258 function verifier_cle_action($action, $cle) {
259 return ($cle == calculer_cle_action($action));
260 }
261
262 ?>