]> git.mjollnir.org Git - moodle.git/commitdiff
MDL-11845 fixed security issues in curl related code in new download_file_content...
authorskodak <skodak>
Mon, 31 Dec 2007 23:18:06 +0000 (23:18 +0000)
committerskodak <skodak>
Mon, 31 Dec 2007 23:18:06 +0000 (23:18 +0000)
lib/filelib.php
lib/snoopy/Snoopy.class.inc

index 6aca3e9f89396336175df7f29e1b1fbce15656bd..f1beef95490f5227cbfeb7c14dbee948995c8ec7 100644 (file)
@@ -4,7 +4,9 @@ define('BYTESERVING_BOUNDARY', 's1k2o3d4a5k6s7'); //unique string constant
 
 /**
  * Fetches content of file from Internet (using proxy if defined). Uses cURL extension if present.
- * @param string $url file url
+ * Due to security concerns only downloads from http(s) sources are supported.
+ *
+ * @param string $url file url starting with http(s)://
  * @param array $headers http headers, null if none
  * @param array $postdata array means use POST request with given parameters
  * @param bool $fullresponse return headers, responses, etc in a similar way snoopy does
@@ -14,6 +16,29 @@ define('BYTESERVING_BOUNDARY', 's1k2o3d4a5k6s7'); //unique string constant
 function download_file_content($url, $headers=null, $postdata=null, $fullresponse=false, $timeout=20) {
     global $CFG;
 
+    // some extra security
+    $newlines = array("\r", "\n");
+    if (is_array($headers) ) {
+        foreach ($headers as $key => $value) {
+            $headers[$key] = str_replace($newlines, '', $value);
+        }
+    }
+    $url = str_replace($newlines, '', $url);
+    if (!preg_match('|^https?://|i', $url)) {
+        if ($fullresponse) {
+            $response = new object();
+            $response->status        = 0;
+            $response->headers       = array();
+            $response->response_code = 'Invalid protocol specified in url';
+            $response->results       = '';
+            $response->error         = 'Invalid protocol specified in url';
+            return $response;
+        } else {
+            return false;
+        }
+    }
+
+
     if (!extension_loaded('curl') or ($ch = curl_init($url)) === false) {
         require_once($CFG->libdir.'/snoopy/Snoopy.class.inc');
         $snoopy = new Snoopy();
@@ -72,12 +97,10 @@ function download_file_content($url, $headers=null, $postdata=null, $fullrespons
         }
     }
 
-    // set extra headers, trim all newlines for extra security
+    // set extra headers
     if (is_array($headers) ) {
         $headers2 = array();
         foreach ($headers as $key => $value) {
-            $value = str_replace("\n", '', $value);
-            $value = str_replace("\r", '', $value);
             $headers2[] = "$key: $value";
         }
         curl_setopt($ch, CURLOPT_HTTPHEADER, $headers2);
@@ -97,7 +120,7 @@ function download_file_content($url, $headers=null, $postdata=null, $fullrespons
     curl_setopt($ch, CURLOPT_HEADER, true);
     curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
     if (!ini_get('open_basedir') and !ini_get('safe_mode')) {
-        // TODO: add version check for '7.10.5'
+        // TODO: add version test for '7.10.5'
         curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
         curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
     }
@@ -108,9 +131,19 @@ function download_file_content($url, $headers=null, $postdata=null, $fullrespons
             if (defined('CURLPROXY_SOCKS5')) {
                 curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
             } else {
-                debugging("SOCKS5 proxies are supported only in PHP5 when cURL extension loaded.", DEBUG_ALL);
                 curl_close($ch);
-                return false;
+                if ($fullresponse) {
+                    $response = new object();
+                    $response->status        = '0';
+                    $response->headers       = array();
+                    $response->response_code = 'SOCKS5 proxy is not supported in PHP4';
+                    $response->results       = '';
+                    $response->error         = 'SOCKS5 proxy is not supported in PHP4';
+                    return $response;
+                } else {
+                    debugging("SOCKS5 proxy is not supported in PHP4.", DEBUG_ALL);
+                    return false;
+                }
             }
         }
 
@@ -131,12 +164,12 @@ function download_file_content($url, $headers=null, $postdata=null, $fullrespons
         }
     }
 
-    $result = curl_exec($ch);
+    $data = curl_exec($ch);
 
-    // detect encoding problems
+    // try to detect encoding problems
     if ((curl_errno($ch) == 23 or curl_errno($ch) == 61) and defined('CURLOPT_ENCODING')) {
         curl_setopt($ch, CURLOPT_ENCODING, 'none');
-        $result = curl_exec($ch);
+        $data = curl_exec($ch);
     }
 
     if (curl_errno($ch)) {
@@ -157,30 +190,42 @@ function download_file_content($url, $headers=null, $postdata=null, $fullrespons
             $response->error         = $error;
             return $response;
         } else {
-            debugging("CURL request for \"$url\" failed with: $error ($error_no)", DEBUG_ALL);
+            debugging("cURL request for \"$url\" failed with: $error ($error_no)", DEBUG_ALL);
             return false;
         }
 
     } else {
         $info = curl_getinfo($ch);
         curl_close($ch);
-        // strip redirect headers and constrct headers array and body
-        $result = explode("\r\n\r\n", $result, $info['redirect_count'] + 2);
-        $results = array_pop($result);
-        $headers = array_pop($result);
-        $headers = explode("\r\n", trim($headers));
-
-        $response = new object();;
-        $response->status        = (string)$info['http_code'];
-        $response->headers       = $headers;
-        $response->response_code = $headers[0];
-        $response->results       = $results;
-        $response->error         = '';
+
+        if (empty($info['http_code'])) {
+            // for security reasons we support only true http connections (Location: file:// exploit prevention)
+            $response = new object();
+            $response->status        = '0';
+            $response->headers       = array();
+            $response->response_code = 'Unknown cURL error';
+            $response->results       = ''; // do NOT change this!
+            $response->error         = 'Unknown cURL error';
+
+        } else {
+            // strip redirect headers and get headers array and content
+            $data = explode("\r\n\r\n", $data, $info['redirect_count'] + 2);
+            $results = array_pop($data);
+            $headers = array_pop($data);
+            $headers = explode("\r\n", trim($headers));
+
+            $response = new object();;
+            $response->status        = (string)$info['http_code'];
+            $response->headers       = $headers;
+            $response->response_code = $headers[0];
+            $response->results       = $results;
+            $response->error         = '';
+        }
 
         if ($fullresponse) {
             return $response;
         } else if ($info['http_code'] != 200) {
-            debugging("CURL request for \"$url\" failed, http response code: $response_code", DEBUG_ALL);
+            debugging("cURL request for \"$url\" failed, HTTP response code: ".$response->response_code, DEBUG_ALL);
             return false;
         } else {
             return $response->results;
index 394a3c676d69911a7b6ab55bf06383aaea32e8d7..b3abbdf898b4f206dc66f1a130447d4a826a7c2f 100644 (file)
@@ -259,7 +259,7 @@ class Snoopy
                 break;
             default:
                 // not a valid protocol
-                $this->error    =    'Invalid protocol "'.$URI_PARTS["scheme"].'"\n';
+                $this->error    =    'Invalid protocol "'.$URI_PARTS["scheme"]; // moodlefix
                 return false;
                 break;
         }        
@@ -425,7 +425,7 @@ class Snoopy
                 
             default:
                 // not a valid protocol
-                $this->error    =    'Invalid protocol "'.$URI_PARTS["scheme"].'"\n';
+                $this->error    =    'Invalid protocol "'.$URI_PARTS["scheme"]; //moodlefix
                 return false;
                 break;
         }        
@@ -720,13 +720,13 @@ class Snoopy
                             chr(176),
                             chr(39),
                             chr(128),
-                            "ä",
-                            "ö",
-                            "ü",
-                            "Ä",
-                            "Ö",
-                            "Ü",
-                            "ß",
+                            "",
+                            "",
+                            "",
+                            "",
+                            "",
+                            "",
+                            "",
                         );
                     
         $text = preg_replace($search,$replace,$document);