Fix path traversal/injection security bug. Thanks to Steven Frank at panic.com for...
[gemini-php] / server.php
1 <?php
2 /*
3  * Gemini server written in PHP by seven@0xm.net
4  * Version 0.1, Oct 2020
5 */
6
7 if(!require("config.php"))
8         die("config.php is missing.  Copy config.php.sample to config.php and customise your settings");
9 require("gemini.class.php");
10 $g = new Gemini($config);
11
12 $context = stream_context_create();
13
14 stream_context_set_option($context, 'ssl', 'local_cert', $g->certificate_file);
15 stream_context_set_option($context, 'ssl', 'passphrase', $g->certificate_passphrase);
16 stream_context_set_option($context, 'ssl', 'allow_self_signed', true);
17 stream_context_set_option($context, 'ssl', 'verify_peer', false);
18
19 $socket = stream_socket_server("tcp://{$g->ip}:{$g->port}", $errno, $errstr, STREAM_SERVER_BIND|STREAM_SERVER_LISTEN, $context);
20
21 stream_socket_enable_crypto($socket, false);
22
23 // apply patch from @nervuri:matrix.org to stop supporting out of spec versions of TLS
24 $cryptoMethod = STREAM_CRYPTO_METHOD_TLS_SERVER
25         & ~ STREAM_CRYPTO_METHOD_TLSv1_0_SERVER
26         & ~ STREAM_CRYPTO_METHOD_TLSv1_1_SERVER;
27
28 while(true) {
29         $forkedSocket = stream_socket_accept($socket, "-1", $remoteIP);
30
31         stream_set_blocking($forkedSocket, true);
32         stream_socket_enable_crypto($forkedSocket, true, $cryptoMethod);
33         $line = fread($forkedSocket, 1024);
34         stream_set_blocking($forkedSocket, false);
35
36         $parsed_url = $g->parse_request($line);
37
38         $filepath = $g->get_filepath($parsed_url);
39
40         $status_code = $g->get_status_code($filepath);
41
42         $meta = "";
43         $filesize = 0;
44
45         if($status_code == "20") {
46                 $meta = $g->get_mime_type($filepath);
47                 $content = file_get_contents($filepath);        
48                 $filesize = filesize($filepath);
49         } else {
50                 $meta = "Not found";
51         }
52
53         $status_line = $status_code." ".$meta;
54         if($g->logging)
55                 $g->log_to_file($remoteIP,$status_code, $meta, $filepath, $filesize);
56         $status_line .= "\r\n";
57         fwrite($forkedSocket, $status_line);
58
59         if($status_code == "20") {
60                 fwrite($forkedSocket,$content);
61         }
62
63         fclose($forkedSocket);
64 }
65
66 ?>