/** * Page d'affichage des résultats de validation XML selon une DTD * * - l'argument var_url peut indiquer un fichier ou un repertoire * - l'argument ext peut valoir "php" ou "html" * -- Si "php", le script est execute et la page valide * -- Si "html", on suppose que c'est un squelette dont on devine les args * en cherchant les occurrences de Pile[0]. * * @example * ``` * ecrire?exec=valider_xml&var_url=exec&ext=php pour tester l'espace prive * ecrire?exec=valider_xml&var_url=../squelettes-dist&ext=html pour le public * ``` * * @uses valider_xml_ok() **/ function exec_valider_xml_dist() { if (!autoriser('webmestre')) { include_spip('inc/minipres'); echo minipres(); } else { $erreur = ""; // verifier que les var de l'URL sont conformes avant d'appeler la fonction $url = trim(_request('var_url')); if (strncmp($url, '/', 1) == 0) { $erreur = 'Chemin absolu interdit pour var_url'; } // on a pas le droit de remonter plus de 1 fois dans le path (pas 2 occurences de ../ ou ..\ (win)) if (($p = strpos($url, '..')) !== false and strpos($url, '..', $p + 3) !== false) { $erreur = 'Interdit de remonter en dehors de la racine'; } if (strpos($url, '://') !== false or strpos($url, ':\\') !== false) { $erreur = 'URL absolue interdite pour var_url'; } $ext = trim(_request('ext')); $ext = ltrim($ext, '.'); // precaution if (preg_match('/\\W/', $ext)) { $erreur = 'Extension invalide'; } // en GET var_url doit etre signee, en POST seule l'action est signee // CSRF safe $process = true; if ($url) { include_spip('inc/securiser_action'); if ($_SERVER["REQUEST_METHOD"] == 'POST') { if (!($token = _request('var_token')) or !verifier_cle_action("valider_xml", $token)) { $process = false; } } if ($_SERVER["REQUEST_METHOD"] != 'POST') { if (!($token = _request('var_token')) or !verifier_cle_action("valider_xml&var_url={$url}", $token)) { $process = false; } } } if ($erreur) { include_spip('inc/minipres'); echo minipres($erreur); } else { valider_xml_ok($url, $ext, intval(_request('limit')), _request('recur'), $process); } } }
/** * Verifie une cle de jeton pour un formulaire * * @param string $jeton * cle recue * @param string $form nom du formulaire * nom du formulaire * @param string $qui * identifiant du visiteur a qui est attribue le jeton * @return bool cle correcte ? */ function verifier_jeton($jeton, $form, $qui = NULL) { $time = time(); $time_old = date('Y-m-d-H', $time - 3600); $time = date('Y-m-d-H', $time); if (is_null($qui)) { if (isset($GLOBALS['visiteur_session']['id_auteur']) and intval($GLOBALS['visiteur_session']['id_auteur'])) { $qui = ":" . $GLOBALS['visiteur_session']['id_auteur'] . ":" . $GLOBALS['visiteur_session']['nom']; } else { $qui = nospam_hash_env(); } } $ok = (verifier_cle_action("jeton{$form}{$time}{$qui}", $jeton) or verifier_cle_action("jeton{$form}{$time_old}{$qui}", $jeton)); #if (!$ok) # spip_log("Erreur form:$form qui:$qui agent:".$_SERVER['HTTP_USER_AGENT']." ip:".$GLOBALS['ip'],'fauxjeton'); return $ok; }
function action_acceder_document_dist() { include_spip('inc/documents'); // $file exige pour eviter le scan id_document par id_document $f = rawurldecode(_request('file')); $file = get_spip_doc($f); $arg = rawurldecode(_request('arg')); $status = $dcc = false; if (strpos($f,'../') !== false OR preg_match(',^\w+://,', $f)) { $status = 403; } else if (!file_exists($file) OR !is_readable($file)) { $status = 404; } else { $where = "documents.fichier=".sql_quote(set_spip_doc($file)) . ($arg ? " AND documents.id_document=".intval($arg): ''); $doc = sql_fetsel("documents.id_document, documents.titre, documents.fichier, types.mime_type, types.inclus, documents.extension", "spip_documents AS documents LEFT JOIN spip_types_documents AS types ON documents.extension=types.extension",$where); if (!$doc) { $status = 404; } else { // ETag pour gerer le status 304 $ETag = md5($file . ': '. filemtime($file)); if (isset($_SERVER['HTTP_IF_NONE_MATCH']) AND $_SERVER['HTTP_IF_NONE_MATCH'] == $ETag) { http_status(304); // Not modified exit; } else { header('ETag: '.$ETag); } // // Verifier les droits de lecture du document // en controlant la cle passee en argument // include_spip('inc/securiser_action'); $cle = _request('cle'); if (!verifier_cle_action($doc['id_document'].','.$f, $cle)) { spip_log("acces interdit $cle erronee"); $status = 403; } } } switch($status) { case 403: include_spip('inc/minipres'); echo minipres(); break; case 404: http_status(404); include_spip('inc/minipres'); echo minipres(_T('erreur').' 404', _T('info_document_indisponible')); break; default: header("Content-Type: ". $doc['mime_type']); // pour les images ne pas passer en attachment // sinon, lorsqu'on pointe directement sur leur adresse, // le navigateur les downloade au lieu de les afficher if ($doc['inclus']=='non') { $f = basename($file); // ce content-type est necessaire pour eviter des corruptions de zip dans ie6 header('Content-Type: application/octet-stream'); header("Content-Disposition: attachment; filename=\"$f\";"); header("Content-Transfer-Encoding: binary"); // fix for IE catching or PHP bug issue header("Pragma: public"); header("Expires: 0"); // set expiration time header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); } if ($cl = filesize($file)) header("Content-Length: ". $cl); readfile($file); break; } }
/** * acces aux documents joints securise * verifie soit que le demandeur est authentifie * soit que le document est publie, c'est-a-dire * joint a au moins 1 article, breve ou rubrique publie * * URLs de la forme : * docrestreint.api/id/cle/file * * @param null $arg */ function action_api_docrestreint_dist($arg = null) { $status = 404; if (is_null($arg)) { $arg = _request('arg'); } $arg = explode("/", $arg); // supprimer et vider les buffers qui posent des problemes de memory limit // http://www.php.net/manual/en/function.readfile.php#81032 @ini_set("zlib.output_compression", "0"); // pour permettre l'affichage au fur et a mesure @ini_set("output_buffering", "off"); @ini_set('implicit_flush', 1); @ob_implicit_flush(1); $level = ob_get_level(); while ($level--) { @ob_end_clean(); } if (count($arg) >= 3) { $id_document = intval(array_shift($arg)); $cle = array_shift($arg); // file exige pour eviter le scan id_document par id_document $f = implode("/", $arg); if ($id_document == 0 and $cle == 1 and $f == "test/.test") { echo "OK"; return; } include_spip('inc/documents'); $file = get_spip_doc($f); spip_log($file, 'dbg'); $status = $dcc = false; $dossiers_a_exclure = array('nl'); // securite : on refuse tout ../ ou url absolue if (strpos($f, '../') !== false or preg_match(',^\\w+://,', $f)) { $status = 403; } else { if (!file_exists($file) or !is_readable($file)) { $status = 404; } elseif (preg_match('%^(' . join('|', $dossiers_a_exclure) . ')/%', $f)) { $status = 200; } else { $where = "documents.fichier=" . sql_quote(set_spip_doc($file)) . ($id_document ? " AND documents.id_document=" . intval($id_document) : ''); spip_log($where, 'dbg'); $doc = sql_fetsel("documents.id_document, documents.titre, documents.fichier, types.mime_type, types.inclus, documents.extension", "spip_documents AS documents LEFT JOIN spip_types_documents AS types ON documents.extension=types.extension", $where); spip_log($doc, 'dbg'); if (!$doc) { $status = 404; } else { // ETag pour gerer le status 304 $ETag = md5($file . ': ' . filemtime($file)); if (isset($_SERVER['HTTP_IF_NONE_MATCH']) and $_SERVER['HTTP_IF_NONE_MATCH'] == $ETag) { http_status(304); // Not modified exit; } else { header('ETag: ' . $ETag); } // // Verifier les droits de lecture du document // en controlant la cle passee en argument si elle est dispo // (perf issue : toutes les urls ont en principe cette cle fournie dans la page au moment du calcul de la page) if ($cle) { include_spip('inc/securiser_action'); if (!verifier_cle_action($doc['id_document'] . ',' . $f, $cle)) { spip_log("acces interdit {$cle} erronee"); $status = 403; } } else { if (!function_exists("autoriser")) { include_spip("inc/autoriser"); } if (!autoriser('voir', 'document', $doc['id_document'])) { $status = 403; spip_log("acces interdit {$cle} erronee"); } } } } } } switch ($status) { case 403: include_spip('inc/minipres'); echo minipres("", "", "", true); break; case 404: http_status(404); include_spip('inc/minipres'); echo minipres(_T('erreur') . ' 404', _T('medias:info_document_indisponible'), "", true); break; default: header("Content-Type: " . $doc['mime_type']); // pour les images ne pas passer en attachment // sinon, lorsqu'on pointe directement sur leur adresse, // le navigateur les downloade au lieu de les afficher if ($doc['inclus'] == 'non') { $f = basename($file); // ce content-type est necessaire pour eviter des corruptions de zip dans ie6 header('Content-Type: application/octet-stream'); header("Content-Disposition: attachment; filename=\"{$f}\";"); header("Content-Transfer-Encoding: binary"); // fix for IE catching or PHP bug issue header("Pragma: public"); header("Expires: 0"); // set expiration time header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); } else { header("Expires: 3600"); // set expiration time } if ($cl = filesize($file)) { header("Content-Length: " . $cl); } readfile($file); break; } }
function action_acceder_document_dist() { include_spip('inc/documents'); // $file exige pour eviter le scan id_document par id_document $f = rawurldecode(_request('file')); $file = get_spip_doc($f); $arg = rawurldecode(_request('arg')); $status = $dcc = false; if (strpos($f,'../') !== false OR preg_match(',^\w+://,', $f)) { $status = 403; } else if (!file_exists($file) OR !is_readable($file)) { $status = 404; } else { $path = set_spip_doc($file); $path2 = generer_acceder_document($f, $arg); $where = "(documents.fichier=".sql_quote($path) . ' OR documents.fichier=' . sql_quote($path2) . ')' . ($arg ? (" AND documents.id_document=".intval($arg)) : ''); $doc = sql_fetsel("documents.id_document, documents.titre, documents.fichier, types.mime_type, types.inclus, documents.extension", "spip_documents AS documents LEFT JOIN spip_types_documents AS types ON documents.extension=types.extension",$where); if (!$doc) { $status = 404; } else { // ETag pour gerer le status 304 $ETag = md5($file . ': '. filemtime($file)); if (isset($_SERVER['HTTP_IF_NONE_MATCH']) AND $_SERVER['HTTP_IF_NONE_MATCH'] == $ETag) { http_status(304); // Not modified exit; } else { header('ETag: '.$ETag); } // // Verifier les droits de lecture du document // en controlant la cle passee en argument // include_spip('inc/securiser_action'); $cle = _request('cle'); if (!verifier_cle_action($doc['id_document'].','.$f, $cle)) { spip_log("acces interdit $cle erronee"); $status = 403; } } } switch($status) { case 403: include_spip('inc/minipres'); echo minipres(); break; case 404: http_status(404); include_spip('inc/minipres'); echo minipres(_T('erreur').' 404', _T('info_document_indisponible')); break; default: header("Content-Type: ". $doc['mime_type']); // Si le fichier a un titre avec extension, // ou si c'est un nom bien connu d'Unix, le prendre // sinon l'ignorer car certains navigateurs pataugent $f = basename($file); if (isset($doc['titre']) AND (preg_match('/^\w+[.]\w+$/', $doc['titre']) OR $doc['titre'] == 'Makefile')) $f = $doc['titre']; $f = "filename=\"$f\""; // Pour les document affichables par les navigateurs, // ne pas envoyer "Content-Disposition: attachment" sinon // le navigateur cree un fichier au lieu de l'afficher. // Mais la propriete "affichable" n'est pas toujours devinable, // il faut quand meme donner un nom au fichier eventuel. // Celui-ci est malheureusement souvent ignore, cf // http://greenbytes.de/tech/tc2231/ if ($doc['inclus']!=='non') { header("Content-Disposition: inline; $f"); } else { header("Content-Disposition: attachment; $f;"); // ce content-type est necessaire // pour eviter des corruptions de zip dans ie6 header('Content-Type: application/octet-stream'); header("Content-Transfer-Encoding: binary"); // fix for IE catching or PHP bug issue header("Pragma: public"); header("Expires: 0"); // set expiration time header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); } if ($cl = filesize($file)) header("Content-Length: ". $cl); readfile($file); break; } }