Blame fish-upstream-CVE-2014-2914-part2.patch

Andy Lutomirski 4de0b6
commit 397249a8d5a939d044da8ecfbb1654d48ce5a153
Andy Lutomirski 4de0b6
Author: David Adam <zanchey@ucc.gu.uwa.edu.au>
Andy Lutomirski 4de0b6
Date:   Mon Aug 4 13:34:26 2014 +0800
Andy Lutomirski 4de0b6
Andy Lutomirski 4de0b6
    Authenticate connections to web_config service
Andy Lutomirski 4de0b6
    
Andy Lutomirski 4de0b6
     - Require all requests to use a session path.
Andy Lutomirski 4de0b6
     - Use a redirect file to avoid exposing the URL on the command line, as
Andy Lutomirski 4de0b6
       it contains the session path.
Andy Lutomirski 4de0b6
    
Andy Lutomirski 4de0b6
    Fix for CVE-2014-2914.
Andy Lutomirski 4de0b6
    Closes #1438.
Andy Lutomirski 4de0b6
Andy Lutomirski 4de0b6
diff --git a/share/tools/web_config/index.html b/share/tools/web_config/index.html
Andy Lutomirski 4de0b6
index 22cd470..90df114 100644
Andy Lutomirski 4de0b6
--- a/share/tools/web_config/index.html
Andy Lutomirski 4de0b6
+++ b/share/tools/web_config/index.html
Andy Lutomirski 4de0b6
@@ -556,7 +556,7 @@ function switch_tab(new_tab) {
Andy Lutomirski 4de0b6
 	if (new_tab == 'tab_colors') {
Andy Lutomirski 4de0b6
 		/* Keep track of whether this is the first element */
Andy Lutomirski 4de0b6
 		var first = true
Andy Lutomirski 4de0b6
-		run_get_request('/colors/', function(key_and_values){
Andy Lutomirski 4de0b6
+		run_get_request('colors/', function(key_and_values){
Andy Lutomirski 4de0b6
 			/* Result is name, description, value */
Andy Lutomirski 4de0b6
 			var key = key_and_values[0]
Andy Lutomirski 4de0b6
 			var description = key_and_values[1]
Andy Lutomirski 4de0b6
@@ -577,7 +577,7 @@ function switch_tab(new_tab) {
Andy Lutomirski 4de0b6
 		sample_prompts.length = 0
Andy Lutomirski 4de0b6
 		/* Color the first one blue */
Andy Lutomirski 4de0b6
 		var first = true;
Andy Lutomirski 4de0b6
-		run_get_request('/sample_prompts/', function(sample_prompt){
Andy Lutomirski 4de0b6
+		run_get_request('sample_prompts/', function(sample_prompt){
Andy Lutomirski 4de0b6
 			var name = sample_prompt['name']
Andy Lutomirski 4de0b6
 			sample_prompts[name] = sample_prompt
Andy Lutomirski 4de0b6
 			var color = first ? '66F' : 'AAA'
Andy Lutomirski 4de0b6
@@ -594,7 +594,7 @@ function switch_tab(new_tab) {
Andy Lutomirski 4de0b6
 	} else if (new_tab == 'tab_functions') {
Andy Lutomirski 4de0b6
 		/* Keep track of whether this is the first element */
Andy Lutomirski 4de0b6
 		var first = true
Andy Lutomirski 4de0b6
-		run_get_request('/functions/', function(contents){
Andy Lutomirski 4de0b6
+		run_get_request('functions/', function(contents){
Andy Lutomirski 4de0b6
 			var elem = create_master_element(contents, false/* description */, 'AAAAAA', '11pt', select_function_master_element)
Andy Lutomirski 4de0b6
 			if (first) {
Andy Lutomirski 4de0b6
 				/* It's the first element, so select it, so something gets selected */
Andy Lutomirski 4de0b6
@@ -606,7 +606,7 @@ function switch_tab(new_tab) {
Andy Lutomirski 4de0b6
 		$('#master_detail_table').show()
Andy Lutomirski 4de0b6
 		wants_data_table = false
Andy Lutomirski 4de0b6
 	} else if (new_tab == 'tab_variables') {
Andy Lutomirski 4de0b6
-		run_get_request_with_bulk_handler('/variables/', function(json_contents){
Andy Lutomirski 4de0b6
+		run_get_request_with_bulk_handler('variables/', function(json_contents){
Andy Lutomirski 4de0b6
 			var rows = new Array()
Andy Lutomirski 4de0b6
 			for (var i = 0; i < json_contents.length; i++) {
Andy Lutomirski 4de0b6
 				var contents = json_contents[i]
Andy Lutomirski 4de0b6
@@ -622,7 +622,7 @@ function switch_tab(new_tab) {
Andy Lutomirski 4de0b6
 	} else if (new_tab == 'tab_history') {
Andy Lutomirski 4de0b6
 		// Clear the history map
Andy Lutomirski 4de0b6
 		history_element_map.length = 0
Andy Lutomirski 4de0b6
-		run_get_request_with_bulk_handler('/history/', function(json_contents){
Andy Lutomirski 4de0b6
+		run_get_request_with_bulk_handler('history/', function(json_contents){
Andy Lutomirski 4de0b6
 			start = new Date().getTime()
Andy Lutomirski 4de0b6
 			var rows = new Array()
Andy Lutomirski 4de0b6
 			for (var i = 0; i < json_contents.length; i++) {
Andy Lutomirski 4de0b6
@@ -757,7 +757,7 @@ function select_color_master_element(elem) {
Andy Lutomirski 4de0b6
 function select_function_master_element(elem) {
Andy Lutomirski 4de0b6
 	select_master_element(elem)
Andy Lutomirski 4de0b6
 	
Andy Lutomirski 4de0b6
-	run_post_request('/get_function/', {
Andy Lutomirski 4de0b6
+	run_post_request('get_function/', {
Andy Lutomirski 4de0b6
 		what: current_master_element_name()
Andy Lutomirski 4de0b6
 	}, function(contents){
Andy Lutomirski 4de0b6
 		/* Replace leading tabs and groups of four spaces at the beginning of a line with two spaces. */
Andy Lutomirski 4de0b6
@@ -773,7 +773,7 @@ function select_sample_prompt_master_element(elem) {
Andy Lutomirski 4de0b6
 	select_master_element(elem)
Andy Lutomirski 4de0b6
 	var name = current_master_element_name()
Andy Lutomirski 4de0b6
 	sample_prompt = sample_prompts[name]
Andy Lutomirski 4de0b6
-	run_post_request('/get_sample_prompt/', {
Andy Lutomirski 4de0b6
+	run_post_request('get_sample_prompt/', {
Andy Lutomirski 4de0b6
 		what: sample_prompt['function']
Andy Lutomirski 4de0b6
 	}, function(keys_and_values){
Andy Lutomirski 4de0b6
 		var prompt_func = keys_and_values['function']
Andy Lutomirski 4de0b6
@@ -788,7 +788,7 @@ function select_sample_prompt_master_element(elem) {
Andy Lutomirski 4de0b6
 function select_current_prompt_master_element(elem) {
Andy Lutomirski 4de0b6
 	$('.prompt_save_button').hide()
Andy Lutomirski 4de0b6
 	select_master_element(elem)
Andy Lutomirski 4de0b6
-	run_get_request_with_bulk_handler('/current_prompt/', function(keys_and_values){
Andy Lutomirski 4de0b6
+	run_get_request_with_bulk_handler('current_prompt/', function(keys_and_values){
Andy Lutomirski 4de0b6
 		var prompt_func = keys_and_values['function']
Andy Lutomirski 4de0b6
 		var prompt_demo = keys_and_values['demo']
Andy Lutomirski 4de0b6
 		var prompt_font_size = keys_and_values['font_size']
Andy Lutomirski 4de0b6
@@ -801,7 +801,7 @@ function select_current_prompt_master_element(elem) {
Andy Lutomirski 4de0b6
 function save_current_prompt() {
Andy Lutomirski 4de0b6
 	var name = current_master_element_name()
Andy Lutomirski 4de0b6
 	var sample_prompt = sample_prompts[name]
Andy Lutomirski 4de0b6
-	run_post_request('/set_prompt/', {
Andy Lutomirski 4de0b6
+	run_post_request('set_prompt/', {
Andy Lutomirski 4de0b6
 		what: sample_prompt['function']
Andy Lutomirski 4de0b6
 	}, function(contents){
Andy Lutomirski 4de0b6
 		if (contents == "OK") {
Andy Lutomirski 4de0b6
@@ -817,7 +817,7 @@ function post_style_to_server() {
Andy Lutomirski 4de0b6
 	if (! style)
Andy Lutomirski 4de0b6
 		return
Andy Lutomirski 4de0b6
 	
Andy Lutomirski 4de0b6
-	run_post_request('/set_color/', {
Andy Lutomirski 4de0b6
+	run_post_request('set_color/', {
Andy Lutomirski 4de0b6
 		what: current_master_element_name(),
Andy Lutomirski 4de0b6
 		color: style.color,
Andy Lutomirski 4de0b6
 		background_color: style.background_color,
Andy Lutomirski 4de0b6
@@ -1221,7 +1221,7 @@ function escape_HTML(foo) {
Andy Lutomirski 4de0b6
 function tell_fish_to_delete_element(idx) {
Andy Lutomirski 4de0b6
 	var row_elem = $('#data_table_row_' + idx)
Andy Lutomirski 4de0b6
 	var txt = history_element_map[idx]
Andy Lutomirski 4de0b6
-	run_post_request('/delete_history_item/', {
Andy Lutomirski 4de0b6
+	run_post_request('delete_history_item/', {
Andy Lutomirski 4de0b6
 		what: txt
Andy Lutomirski 4de0b6
 	}, function(contents){
Andy Lutomirski 4de0b6
 		if (contents == "OK") {
Andy Lutomirski 4de0b6
diff --git a/share/tools/web_config/webconfig.py b/share/tools/web_config/webconfig.py
Andy Lutomirski 4de0b6
index 1b9250b..2a103eb 100755
Andy Lutomirski 4de0b6
--- a/share/tools/web_config/webconfig.py
Andy Lutomirski 4de0b6
+++ b/share/tools/web_config/webconfig.py
Andy Lutomirski 4de0b6
@@ -17,7 +17,7 @@ else:
Andy Lutomirski 4de0b6
     from urllib.parse import parse_qs
Andy Lutomirski 4de0b6
 import webbrowser
Andy Lutomirski 4de0b6
 import subprocess
Andy Lutomirski 4de0b6
-import re, socket, os, sys, cgi, select, time, glob
Andy Lutomirski 4de0b6
+import re, socket, os, sys, cgi, select, time, glob, random, string
Andy Lutomirski 4de0b6
 try:
Andy Lutomirski 4de0b6
     import json
Andy Lutomirski 4de0b6
 except ImportError:
Andy Lutomirski 4de0b6
@@ -485,9 +485,16 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
Andy Lutomirski 4de0b6
         else: font_size = '18pt'
Andy Lutomirski 4de0b6
         return font_size
Andy Lutomirski 4de0b6
 
Andy Lutomirski 4de0b6
-
Andy Lutomirski 4de0b6
     def do_GET(self):
Andy Lutomirski 4de0b6
         p = self.path
Andy Lutomirski 4de0b6
+
Andy Lutomirski 4de0b6
+        authpath = '/' + authkey
Andy Lutomirski 4de0b6
+        if p.startswith(authpath):
Andy Lutomirski 4de0b6
+            p = p[len(authpath):]
Andy Lutomirski 4de0b6
+        else:
Andy Lutomirski 4de0b6
+            return self.send_error(403)
Andy Lutomirski 4de0b6
+        self.path = p
Andy Lutomirski 4de0b6
+
Andy Lutomirski 4de0b6
         if p == '/colors/':
Andy Lutomirski 4de0b6
             output = self.do_get_colors()
Andy Lutomirski 4de0b6
         elif p == '/functions/':
Andy Lutomirski 4de0b6
@@ -519,6 +526,14 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
Andy Lutomirski 4de0b6
 
Andy Lutomirski 4de0b6
     def do_POST(self):
Andy Lutomirski 4de0b6
         p = self.path
Andy Lutomirski 4de0b6
+
Andy Lutomirski 4de0b6
+        authpath = '/' + authkey
Andy Lutomirski 4de0b6
+        if p.startswith(authpath):
Andy Lutomirski 4de0b6
+            p = p[len(authpath):]
Andy Lutomirski 4de0b6
+        else:
Andy Lutomirski 4de0b6
+            return self.send_error(403)
Andy Lutomirski 4de0b6
+        self.path = p
Andy Lutomirski 4de0b6
+
Andy Lutomirski 4de0b6
         if IS_PY2:
Andy Lutomirski 4de0b6
             ctype, pdict = cgi.parse_header(self.headers.getheader('content-type'))
Andy Lutomirski 4de0b6
         else: # Python 3
Andy Lutomirski 4de0b6
@@ -582,7 +597,19 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
Andy Lutomirski 4de0b6
     def log_request(self, code='-', size='-'):
Andy Lutomirski 4de0b6
         """ Disable request logging """
Andy Lutomirski 4de0b6
         pass
Andy Lutomirski 4de0b6
-        
Andy Lutomirski 4de0b6
+
Andy Lutomirski 4de0b6
+redirect_template_html = """
Andy Lutomirski 4de0b6
+
Andy Lutomirski 4de0b6
+<html>
Andy Lutomirski 4de0b6
+ <head>
Andy Lutomirski 4de0b6
+  <meta http-equiv="refresh" content="0;URL='%s'" />
Andy Lutomirski 4de0b6
+ </head>
Andy Lutomirski 4de0b6
+ <body>
Andy Lutomirski 4de0b6
+  

Start the Fish Web config

Andy Lutomirski 4de0b6
+ </body>
Andy Lutomirski 4de0b6
+</html>
Andy Lutomirski 4de0b6
+"""
Andy Lutomirski 4de0b6
+
Andy Lutomirski 4de0b6
 # find fish
Andy Lutomirski 4de0b6
 fish_bin_dir = os.environ.get('__fish_bin_dir')
Andy Lutomirski 4de0b6
 fish_bin_path = None
Andy Lutomirski 4de0b6
@@ -618,6 +645,9 @@ initial_wd = os.getcwd()
Andy Lutomirski 4de0b6
 where = os.path.dirname(sys.argv[0])
Andy Lutomirski 4de0b6
 os.chdir(where)
Andy Lutomirski 4de0b6
 
Andy Lutomirski 4de0b6
+# Generate a 16-byte random key as a hexadecimal string
Andy Lutomirski 4de0b6
+authkey = hex(random.getrandbits(16*4))[2:]
Andy Lutomirski 4de0b6
+
Andy Lutomirski 4de0b6
 # Try to find a suitable port
Andy Lutomirski 4de0b6
 PORT = 8000
Andy Lutomirski 4de0b6
 while PORT <= 9000:
Andy Lutomirski 4de0b6
@@ -647,9 +677,36 @@ if len(sys.argv) > 1:
Andy Lutomirski 4de0b6
             initial_tab = '#' + tab
Andy Lutomirski 4de0b6
             break
Andy Lutomirski 4de0b6
 
Andy Lutomirski 4de0b6
-url = 'http://localhost:%d/%s' % (PORT, initial_tab)
Andy Lutomirski 4de0b6
-print("Web config started at '%s'. Hit enter to stop." % url)
Andy Lutomirski 4de0b6
-webbrowser.open(url)
Andy Lutomirski 4de0b6
+url = 'http://localhost:%d/%s/%s' % (PORT, authkey, initial_tab)
Andy Lutomirski 4de0b6
+
Andy Lutomirski 4de0b6
+# Create temporary file to hold redirect to real server
Andy Lutomirski 4de0b6
+# This prevents exposing the URL containing the authentication key on the command line
Andy Lutomirski 4de0b6
+# (see CVE-2014-2914 or https://github.com/fish-shell/fish-shell/issues/1438)
Andy Lutomirski 4de0b6
+if 'XDG_CACHE_HOME' in os.environ:
Andy Lutomirski 4de0b6
+    dirname = os.path.expanduser(os.path.expandvars('$XDG_CACHE_HOME/fish/'))
Andy Lutomirski 4de0b6
+else:
Andy Lutomirski 4de0b6
+    dirname = os.path.expanduser('~/.cache/fish/')
Andy Lutomirski 4de0b6
+
Andy Lutomirski 4de0b6
+os.umask(0o0077)
Andy Lutomirski 4de0b6
+try:
Andy Lutomirski 4de0b6
+    os.makedirs(dirname, 0o0700)
Andy Lutomirski 4de0b6
+except OSError as e:
Andy Lutomirski 4de0b6
+    if e.errno == 17:
Andy Lutomirski 4de0b6
+       pass
Andy Lutomirski 4de0b6
+    else:
Andy Lutomirski 4de0b6
+       raise e
Andy Lutomirski 4de0b6
+
Andy Lutomirski 4de0b6
+randtoken = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6))
Andy Lutomirski 4de0b6
+filename = dirname + 'web_config-%s.html' % randtoken
Andy Lutomirski 4de0b6
+
Andy Lutomirski 4de0b6
+f = open(filename, 'w')
Andy Lutomirski 4de0b6
+f.write(redirect_template_html % (url, url))
Andy Lutomirski 4de0b6
+f.close()
Andy Lutomirski 4de0b6
+
Andy Lutomirski 4de0b6
+# Open temporary file as URL
Andy Lutomirski 4de0b6
+fileurl = 'file://' + filename
Andy Lutomirski 4de0b6
+print("Web config started at '%s'. Hit enter to stop." % fileurl)
Andy Lutomirski 4de0b6
+webbrowser.open(fileurl)
Andy Lutomirski 4de0b6
 
Andy Lutomirski 4de0b6
 # Select on stdin and httpd
Andy Lutomirski 4de0b6
 stdin_no = sys.stdin.fileno()
Andy Lutomirski 4de0b6
@@ -666,3 +723,5 @@ try:
Andy Lutomirski 4de0b6
 except KeyboardInterrupt:
Andy Lutomirski 4de0b6
     print("\nShutting down.")
Andy Lutomirski 4de0b6
 
Andy Lutomirski 4de0b6
+# Clean up temporary file
Andy Lutomirski 4de0b6
+os.remove(filename)