[SPIP] v3.2.1-->v3.2.2
[lhc/web/www.git] / www / ecrire / inc / distant.php
index 266ba95..cf35ca7 100644 (file)
@@ -3,7 +3,7 @@
 /***************************************************************************\
  *  SPIP, Systeme de publication pour l'internet                           *
  *                                                                         *
- *  Copyright (c) 2001-2017                                                *
+ *  Copyright (c) 2001-2019                                                *
  *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
  *                                                                         *
  *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
@@ -141,6 +141,102 @@ function copie_locale($source, $mode = 'auto', $local = null, $taille_max = null
        return $local;
 }
 
+/**
+ * Valider qu'une URL d'un document distant est bien distante
+ * et pas une url localhost qui permet d'avoir des infos sur le serveur
+ * inspiree de https://core.trac.wordpress.org/browser/trunk/src/wp-includes/http.php?rev=36435#L500
+ * 
+ * @param string $url
+ * @param array $known_hosts
+ *   url/hosts externes connus et acceptes
+ * @return false|string 
+ *   url ou false en cas d'echec
+ */
+function valider_url_distante($url, $known_hosts = array()) {
+       if (!function_exists('protocole_verifier')){
+               include_spip('inc/filtres_mini');
+       }
+
+       if (!protocole_verifier($url, array('http', 'https'))) {
+               return false;
+       }
+       
+       $parsed_url = parse_url($url);
+       if (!$parsed_url or empty($parsed_url['host']) ) {
+               return false;
+       }
+
+       if (isset($parsed_url['user']) or isset($parsed_url['pass'])) {
+               return false;
+       }
+
+       if (false !== strpbrk($parsed_url['host'], ':#?[]')) {
+               return false;
+       }
+
+       if (!is_array($known_hosts)) {
+               $known_hosts = array($known_hosts);
+       }
+       $known_hosts[] = $GLOBALS['meta']['adresse_site'];
+       $known_hosts[] = url_de_base();
+       $known_hosts = pipeline('declarer_hosts_distants', $known_hosts);
+
+       $is_known_host = false;
+       foreach ($known_hosts as $known_host) {
+               $parse_known = parse_url($known_host);
+               if ($parse_known
+                 and strtolower($parse_known['host']) === strtolower($parsed_url['host'])) {
+                       $is_known_host = true;
+                       break;
+               }
+       }
+
+       if (!$is_known_host) {
+               $host = trim($parsed_url['host'], '.');
+               if (preg_match('#^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$#', $host)) {
+                       $ip = $host;
+               } else {
+                       $ip = gethostbyname($host);
+                       if ($ip === $host) {
+                               // Error condition for gethostbyname()
+                               $ip = false;
+                       }
+               }
+               if ($ip) {
+                       $parts = array_map('intval', explode( '.', $ip ));
+                       if (127 === $parts[0] or 10 === $parts[0] or 0 === $parts[0]
+                         or ( 172 === $parts[0] and 16 <= $parts[1] and 31 >= $parts[1] )
+                         or ( 192 === $parts[0] && 168 === $parts[1] )
+                       ) {
+                               return false;
+                       }
+               }
+       }
+
+       if (empty($parsed_url['port'])) {
+               return $url;
+       }
+
+       $port = $parsed_url['port'];
+       if ($port === 80  or $port === 443  or $port === 8080) {
+               return $url;
+       }
+
+       if ($is_known_host) {
+               foreach ($known_hosts as $known_host) {
+                       $parse_known = parse_url($known_host);
+                       if ($parse_known
+                               and !empty($parse_known['port'])
+                         and strtolower($parse_known['host']) === strtolower($parsed_url['host'])
+                         and $parse_known['port'] == $port) {
+                               return $url;
+                       }
+               }
+       }
+
+       return false;
+}
+
 /**
  * Preparer les donnes pour un POST
  * si $donnees est une chaine
@@ -448,6 +544,7 @@ function recuperer_url($url, $options = array()) {
                        $result['page'] = &$res;
                        $result['length'] = strlen($result['page']);
                }
+               $result['status'] = 200; // on a reussi, donc !
        }
        if (!$result['page']) {
                return $result;
@@ -1140,16 +1237,42 @@ function need_proxy($host, $http_proxy = null, $http_noproxy = null) {
        if (is_null($http_proxy)) {
                $http_proxy = isset($GLOBALS['meta']['http_proxy']) ? $GLOBALS['meta']['http_proxy'] : null;
        }
+       // rien a faire si pas de proxy :)
+       if (is_null($http_proxy) or !$http_proxy = trim($http_proxy)) {
+               return '';
+       }
+
        if (is_null($http_noproxy)) {
                $http_noproxy = isset($GLOBALS['meta']['http_noproxy']) ? $GLOBALS['meta']['http_noproxy'] : null;
        }
+       // si pas d'exception, on retourne le proxy
+       if (is_null($http_noproxy) or !$http_noproxy = trim($http_noproxy)) {
+               return $http_proxy;
+       }
+
+       // si le host ou l'un des domaines parents est dans $http_noproxy on fait exception
+       // $http_noproxy peut contenir plusieurs domaines separes par des espaces ou retour ligne
+       $http_noproxy = str_replace("\n", " ", $http_noproxy);
+       $http_noproxy = str_replace("\r", " ", $http_noproxy);
+       $http_noproxy = " $http_noproxy ";
+       $domain = $host;
+       // si le domaine exact www.example.org est dans les exceptions
+       if (strpos($http_noproxy, " $domain ") !== false)
+               return '';
+
+       while (strpos($domain, '.') !== false) {
+               $domain = explode('.', $domain);
+               array_shift($domain);
+               $domain = implode('.', $domain);
+
+               // ou si un domaine parent commencant par un . est dans les exceptions (indiquant qu'il couvre tous les sous-domaines)
+               if (strpos($http_noproxy, " .$domain ") !== false) {
+                       return '';
+               }
+       }
 
-       $domain = substr($host, strpos($host, '.'));
-
-       return ($http_proxy
-               and (strpos(" $http_noproxy ", " $host ") === false
-                       and (strpos(" $http_noproxy ", " $domain ") === false)))
-               ? $http_proxy : '';
+       // ok c'est pas une exception
+       return $http_proxy;
 }
 
 
@@ -1181,8 +1304,8 @@ function init_http($method, $url, $refuse_gz = false, $referer = '', $datas = ''
                $scheme = 'http';
                $noproxy = '';
        } elseif ($t['scheme'] == 'https') {
-               $scheme = 'tls';
-               $noproxy = 'tls://';
+               $scheme = 'ssl';
+               $noproxy = 'ssl://';
                if (!isset($t['port']) || !($port = $t['port'])) {
                        $t['port'] = 443;
                }
@@ -1280,13 +1403,13 @@ function lance_requete(
 
        $connect = '';
        if ($http_proxy) {
-               if (defined('_PROXY_HTTPS_VIA_CONNECT') and $scheme == 'tls') {
+               if (defined('_PROXY_HTTPS_VIA_CONNECT') and in_array($scheme , array('tls','ssl'))) {
                        $path_host = (!$user ? '' : "$user@") . $host . (($port != 80) ? ":$port" : '');
                        $connect = 'CONNECT ' . $path_host . " $vers\r\n"
                                . "Host: $path_host\r\n"
                                . "Proxy-Connection: Keep-Alive\r\n";
                } else {
-                       $path = (($scheme == 'tls') ? 'https://' : "$scheme://")
+                       $path = (in_array($scheme , array('tls','ssl')) ? 'https://' : "$scheme://")
                                . (!$user ? '' : "$user@")
                                . "$host" . (($port != 80) ? ":$port" : '') . $path;
                }
@@ -1362,8 +1485,12 @@ function lance_requete(
 
        $site = isset($GLOBALS['meta']['adresse_site']) ? $GLOBALS['meta']['adresse_site'] : '';
 
+       $host_port = $host;
+       if ($port != (in_array($scheme , array('tls','ssl')) ? 443 : 80)) {
+               $host_port .= ":$port";
+       }
        $req = "$method $path $vers\r\n"
-               . "Host: $host\r\n"
+               . "Host: $host_port\r\n"
                . 'User-Agent: ' . _INC_DISTANT_USER_AGENT . "\r\n"
                . ($refuse_gz ? '' : ('Accept-Encoding: ' . _INC_DISTANT_CONTENT_ENCODING . "\r\n"))
                . (!$site ? '' : "Referer: $site/$referer\r\n")