parent
e861ac7b15
commit
547de75695
@ -1 +1,2 @@
|
|||||||
/fish-2.1.0.tar.gz
|
/fish-2.1.0.tar.gz
|
||||||
|
/fish-2.1.1.tar.gz
|
||||||
|
@ -1,185 +0,0 @@
|
|||||||
From b5cd21c337a8990c0c343ab2c22d3dc123a03d25 Mon Sep 17 00:00:00 2001
|
|
||||||
Message-Id: <b5cd21c337a8990c0c343ab2c22d3dc123a03d25.1407803973.git.luto@amacapital.net>
|
|
||||||
From: David Adam <zanchey@ucc.gu.uwa.edu.au>
|
|
||||||
Date: Mon, 4 Aug 2014 13:26:14 +0800
|
|
||||||
Subject: [PATCH 1/3] Further fixes to universal variable server socket
|
|
||||||
management
|
|
||||||
|
|
||||||
- Change fishd_path to std::string
|
|
||||||
- Warn, rather than exiting with an error, if the universal variable
|
|
||||||
server path is not available, and provide more useful advice.
|
|
||||||
- Export the new __fishd_runtime_dir variable.
|
|
||||||
---
|
|
||||||
common.cpp | 13 +++++++------
|
|
||||||
common.h | 2 +-
|
|
||||||
env.cpp | 4 ++--
|
|
||||||
env_universal.cpp | 22 ++++++++++++++--------
|
|
||||||
env_universal.h | 2 +-
|
|
||||||
fish_pager.cpp | 4 ++--
|
|
||||||
fishd.cpp | 9 +++++++--
|
|
||||||
7 files changed, 34 insertions(+), 22 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/common.cpp b/common.cpp
|
|
||||||
index 3e5a2c8..203eda5 100644
|
|
||||||
--- a/common.cpp
|
|
||||||
+++ b/common.cpp
|
|
||||||
@@ -2381,10 +2381,11 @@ static int check_runtime_path(const char * path)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Return the path of an appropriate runtime data directory */
|
|
||||||
-const char* common_get_runtime_path(void)
|
|
||||||
+std::string common_get_runtime_path()
|
|
||||||
{
|
|
||||||
const char *dir = getenv("XDG_RUNTIME_DIR");
|
|
||||||
const char *uname = getenv("USER");
|
|
||||||
+ std::string path;
|
|
||||||
|
|
||||||
if (uname == NULL)
|
|
||||||
{
|
|
||||||
@@ -2396,19 +2397,19 @@ const char* common_get_runtime_path(void)
|
|
||||||
{
|
|
||||||
// /tmp/fish.user
|
|
||||||
dir = "/tmp/fish.";
|
|
||||||
- std::string path;
|
|
||||||
path.reserve(strlen(dir) + strlen(uname));
|
|
||||||
path.append(dir);
|
|
||||||
path.append(uname);
|
|
||||||
if (check_runtime_path(path.c_str()) != 0)
|
|
||||||
{
|
|
||||||
- debug(0, L"Couldn't create secure runtime path: '%s'", path.c_str());
|
|
||||||
- exit(EXIT_FAILURE);
|
|
||||||
+ debug(0, L"Runtime path not available. Try deleting the directory %s and restarting fish.", path.c_str());
|
|
||||||
+ path.clear();
|
|
||||||
}
|
|
||||||
- return strdup(path.c_str());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
- return dir;
|
|
||||||
+ path.reserve(strlen(dir));
|
|
||||||
+ path.append(dir);
|
|
||||||
}
|
|
||||||
+ return path;
|
|
||||||
}
|
|
||||||
diff --git a/common.h b/common.h
|
|
||||||
index 4d18aca..b160245 100644
|
|
||||||
--- a/common.h
|
|
||||||
+++ b/common.h
|
|
||||||
@@ -814,6 +814,6 @@ extern "C" {
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Return the path of an appropriate runtime data directory */
|
|
||||||
-const char* common_get_runtime_path(void);
|
|
||||||
+std::string common_get_runtime_path();
|
|
||||||
|
|
||||||
#endif
|
|
||||||
diff --git a/env.cpp b/env.cpp
|
|
||||||
index 0bda417..703d619 100644
|
|
||||||
--- a/env.cpp
|
|
||||||
+++ b/env.cpp
|
|
||||||
@@ -620,8 +620,8 @@ void env_init(const struct config_paths_t *paths /* or NULL */)
|
|
||||||
|
|
||||||
const env_var_t user_dir_wstr = env_get_string(L"USER");
|
|
||||||
|
|
||||||
- const char * fishd_dir = common_get_runtime_path();
|
|
||||||
- env_set(L"__fish_runtime_dir", str2wcstring(fishd_dir).c_str(), ENV_GLOBAL);
|
|
||||||
+ std::string fishd_dir = common_get_runtime_path();
|
|
||||||
+ env_set(L"__fish_runtime_dir", str2wcstring(fishd_dir).c_str(), ENV_GLOBAL | ENV_EXPORT);
|
|
||||||
|
|
||||||
wchar_t * user_dir = user_dir_wstr.missing()?NULL:const_cast<wchar_t*>(user_dir_wstr.c_str());
|
|
||||||
|
|
||||||
diff --git a/env_universal.cpp b/env_universal.cpp
|
|
||||||
index 1a97443..78e3130 100644
|
|
||||||
--- a/env_universal.cpp
|
|
||||||
+++ b/env_universal.cpp
|
|
||||||
@@ -242,23 +242,29 @@ static void reconnect()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
-void env_universal_init(const char * p,
|
|
||||||
+void env_universal_init(std::string p,
|
|
||||||
wchar_t *u,
|
|
||||||
void (*sf)(),
|
|
||||||
void (*cb)(fish_message_type_t type, const wchar_t *name, const wchar_t *val))
|
|
||||||
{
|
|
||||||
- path=p;
|
|
||||||
+ path=p.c_str();
|
|
||||||
user=u;
|
|
||||||
start_fishd=sf;
|
|
||||||
external_callback = cb;
|
|
||||||
|
|
||||||
- env_universal_server.fd = get_socket();
|
|
||||||
- env_universal_common_init(&callback);
|
|
||||||
- env_universal_read_all();
|
|
||||||
- s_env_univeral_inited = true;
|
|
||||||
- if (env_universal_server.fd >= 0)
|
|
||||||
+ if (p == "") {
|
|
||||||
+ debug(1, L"Could not connect to universal variable server. You will not be able to share variable values between fish sessions.");
|
|
||||||
+ }
|
|
||||||
+ else
|
|
||||||
{
|
|
||||||
- env_universal_barrier();
|
|
||||||
+ env_universal_server.fd = get_socket();
|
|
||||||
+ env_universal_common_init(&callback);
|
|
||||||
+ env_universal_read_all();
|
|
||||||
+ s_env_univeral_inited = true;
|
|
||||||
+ if (env_universal_server.fd >= 0)
|
|
||||||
+ {
|
|
||||||
+ env_universal_barrier();
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
diff --git a/env_universal.h b/env_universal.h
|
|
||||||
index 9e6ab85..f14db29 100644
|
|
||||||
--- a/env_universal.h
|
|
||||||
+++ b/env_universal.h
|
|
||||||
@@ -17,7 +17,7 @@ extern connection_t env_universal_server;
|
|
||||||
/**
|
|
||||||
Initialize the envuni library
|
|
||||||
*/
|
|
||||||
-void env_universal_init(const char * p,
|
|
||||||
+void env_universal_init(std::string p,
|
|
||||||
wchar_t *u,
|
|
||||||
void (*sf)(),
|
|
||||||
void (*cb)(fish_message_type_t type, const wchar_t *name, const wchar_t *val));
|
|
||||||
diff --git a/fish_pager.cpp b/fish_pager.cpp
|
|
||||||
index 27bc80e..6d05774 100644
|
|
||||||
--- a/fish_pager.cpp
|
|
||||||
+++ b/fish_pager.cpp
|
|
||||||
@@ -1032,8 +1032,8 @@ static void init(int mangle_descriptors, int out)
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
-
|
|
||||||
- env_universal_init("", 0, 0, 0);
|
|
||||||
+ std::string dir = common_get_runtime_path();
|
|
||||||
+ env_universal_init(dir, 0, 0, 0);
|
|
||||||
input_common_init(&interrupt_handler);
|
|
||||||
output_set_writer(&pager_buffered_writer);
|
|
||||||
|
|
||||||
diff --git a/fishd.cpp b/fishd.cpp
|
|
||||||
index dd43647..d725e43 100644
|
|
||||||
--- a/fishd.cpp
|
|
||||||
+++ b/fishd.cpp
|
|
||||||
@@ -159,10 +159,15 @@ static int quit=0;
|
|
||||||
*/
|
|
||||||
static std::string get_socket_filename(void)
|
|
||||||
{
|
|
||||||
- const char *dir = common_get_runtime_path();
|
|
||||||
+ std::string dir = common_get_runtime_path();
|
|
||||||
+
|
|
||||||
+ if (dir == "") {
|
|
||||||
+ debug(0, L"Cannot access desired socket path.");
|
|
||||||
+ exit(EXIT_FAILURE);
|
|
||||||
+ }
|
|
||||||
|
|
||||||
std::string name;
|
|
||||||
- name.reserve(strlen(dir) + strlen(SOCK_FILENAME) + 1);
|
|
||||||
+ name.reserve(dir.length() + strlen(SOCK_FILENAME) + 1);
|
|
||||||
name.append(dir);
|
|
||||||
name.push_back('/');
|
|
||||||
name.append(SOCK_FILENAME);
|
|
||||||
--
|
|
||||||
1.9.3
|
|
||||||
|
|
@ -1,478 +0,0 @@
|
|||||||
From 4cb4fc3ef889788b9755451bc565e27bb803b8ba Mon Sep 17 00:00:00 2001
|
|
||||||
Message-Id: <4cb4fc3ef889788b9755451bc565e27bb803b8ba.1407803923.git.luto@amacapital.net>
|
|
||||||
From: David Adam <zanchey@ucc.gu.uwa.edu.au>
|
|
||||||
Date: Sun, 20 Apr 2014 19:20:07 +0800
|
|
||||||
Subject: [PATCH] Fix for CVE-2014-2905 - fishd restart required.
|
|
||||||
|
|
||||||
- Use a secure path for sockets (some code used under license from
|
|
||||||
tmux).
|
|
||||||
- Provide the secure path in the environment as $__fish_runtime_dir.
|
|
||||||
- Link the new path to the old path to ease migration from earlier
|
|
||||||
versions.
|
|
||||||
|
|
||||||
Closes #1359.
|
|
||||||
|
|
||||||
After installing fish built from or after this commit, you MUST
|
|
||||||
terminate all running fishd processes (`killall fishd`, `pkill fishd`
|
|
||||||
or similar). Distributors are encouraged to do this from within their
|
|
||||||
packaging scripts. fishd will restart automatically, and no data should
|
|
||||||
be lost.
|
|
||||||
---
|
|
||||||
common.cpp | 70 ++++++++++++++++++++++++++++++++++++++++++++++++
|
|
||||||
common.h | 2 ++
|
|
||||||
doc_src/license.hdr | 20 ++++++++++++++
|
|
||||||
env.cpp | 7 ++---
|
|
||||||
env_universal.cpp | 41 +++++-----------------------
|
|
||||||
env_universal.h | 2 +-
|
|
||||||
env_universal_common.cpp | 10 +++++--
|
|
||||||
env_universal_common.h | 9 +++++--
|
|
||||||
fish_pager.cpp | 2 +-
|
|
||||||
fishd.cpp | 56 +++++++++++++++++++++++++++++++++++---
|
|
||||||
10 files changed, 172 insertions(+), 47 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/common.cpp b/common.cpp
|
|
||||||
index 7a9f7a5..3e5a2c8 100644
|
|
||||||
--- a/common.cpp
|
|
||||||
+++ b/common.cpp
|
|
||||||
@@ -24,6 +24,7 @@ parts of fish.
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
+#include <pwd.h>
|
|
||||||
|
|
||||||
#ifdef HAVE_SYS_IOCTL_H
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
@@ -2342,3 +2343,72 @@ char **make_null_terminated_array(const std::vector<std::string> &lst)
|
|
||||||
{
|
|
||||||
return make_null_terminated_array_helper(lst);
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+/**
|
|
||||||
+ Check, and create if necessary, a secure runtime path
|
|
||||||
+ Derived from tmux.c in tmux (http://tmux.sourceforge.net/)
|
|
||||||
+*/
|
|
||||||
+static int check_runtime_path(const char * path)
|
|
||||||
+{
|
|
||||||
+ /*
|
|
||||||
+ * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
|
||||||
+ *
|
|
||||||
+ * Permission to use, copy, modify, and distribute this software for any
|
|
||||||
+ * purpose with or without fee is hereby granted, provided that the above
|
|
||||||
+ * copyright notice and this permission notice appear in all copies.
|
|
||||||
+ *
|
|
||||||
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
|
||||||
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
|
||||||
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+ struct stat statpath;
|
|
||||||
+ u_int uid = geteuid();
|
|
||||||
+
|
|
||||||
+ if (mkdir(path, S_IRWXU) != 0 && errno != EEXIST)
|
|
||||||
+ return errno;
|
|
||||||
+ if (lstat(path, &statpath) != 0)
|
|
||||||
+ return errno;
|
|
||||||
+ if (!S_ISDIR(statpath.st_mode)
|
|
||||||
+ || statpath.st_uid != uid
|
|
||||||
+ || (statpath.st_mode & (S_IRWXG|S_IRWXO)) != 0)
|
|
||||||
+ return EACCES;
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/** Return the path of an appropriate runtime data directory */
|
|
||||||
+const char* common_get_runtime_path(void)
|
|
||||||
+{
|
|
||||||
+ const char *dir = getenv("XDG_RUNTIME_DIR");
|
|
||||||
+ const char *uname = getenv("USER");
|
|
||||||
+
|
|
||||||
+ if (uname == NULL)
|
|
||||||
+ {
|
|
||||||
+ const struct passwd *pw = getpwuid(getuid());
|
|
||||||
+ uname = pw->pw_name;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (dir == NULL)
|
|
||||||
+ {
|
|
||||||
+ // /tmp/fish.user
|
|
||||||
+ dir = "/tmp/fish.";
|
|
||||||
+ std::string path;
|
|
||||||
+ path.reserve(strlen(dir) + strlen(uname));
|
|
||||||
+ path.append(dir);
|
|
||||||
+ path.append(uname);
|
|
||||||
+ if (check_runtime_path(path.c_str()) != 0)
|
|
||||||
+ {
|
|
||||||
+ debug(0, L"Couldn't create secure runtime path: '%s'", path.c_str());
|
|
||||||
+ exit(EXIT_FAILURE);
|
|
||||||
+ }
|
|
||||||
+ return strdup(path.c_str());
|
|
||||||
+ }
|
|
||||||
+ else
|
|
||||||
+ {
|
|
||||||
+ return dir;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
diff --git a/common.h b/common.h
|
|
||||||
index 57fe7fa..4d18aca 100644
|
|
||||||
--- a/common.h
|
|
||||||
+++ b/common.h
|
|
||||||
@@ -813,5 +813,7 @@ extern "C" {
|
|
||||||
__attribute__((noinline)) void debug_thread_error(void);
|
|
||||||
}
|
|
||||||
|
|
||||||
+/** Return the path of an appropriate runtime data directory */
|
|
||||||
+const char* common_get_runtime_path(void);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
diff --git a/doc_src/license.hdr b/doc_src/license.hdr
|
|
||||||
index 64bab10..76981a9 100644
|
|
||||||
--- a/doc_src/license.hdr
|
|
||||||
+++ b/doc_src/license.hdr
|
|
||||||
@@ -1400,6 +1400,26 @@ POSSIBILITY OF SUCH DAMAGES.
|
|
||||||
|
|
||||||
<P>
|
|
||||||
|
|
||||||
+<h2>License for code derived from tmux</h2>
|
|
||||||
+
|
|
||||||
+Fish contains code derived from
|
|
||||||
+<a href="http://tmux.sourceforge.net">tmux</a>, made available under an ISC
|
|
||||||
+license.
|
|
||||||
+<p>
|
|
||||||
+Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
|
||||||
+<p>
|
|
||||||
+Permission to use, copy, modify, and distribute this software for any
|
|
||||||
+purpose with or without fee is hereby granted, provided that the above
|
|
||||||
+copyright notice and this permission notice appear in all copies.
|
|
||||||
+<p>
|
|
||||||
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
+WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
|
||||||
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
|
||||||
+OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
+
|
|
||||||
*/
|
|
||||||
|
|
||||||
\htmlonly </div> \endhtmlonly
|
|
||||||
diff --git a/env.cpp b/env.cpp
|
|
||||||
index 13f87b6..0bda417 100644
|
|
||||||
--- a/env.cpp
|
|
||||||
+++ b/env.cpp
|
|
||||||
@@ -57,7 +57,7 @@
|
|
||||||
#include "complete.h"
|
|
||||||
|
|
||||||
/** Command used to start fishd */
|
|
||||||
-#define FISHD_CMD L"fishd ^ /tmp/fishd.log.%s"
|
|
||||||
+#define FISHD_CMD L"fishd ^ $__fish_runtime_dir/fishd.log.%s"
|
|
||||||
|
|
||||||
// Version for easier debugging
|
|
||||||
//#define FISHD_CMD L"fishd"
|
|
||||||
@@ -618,10 +618,11 @@ void env_init(const struct config_paths_t *paths /* or NULL */)
|
|
||||||
env_set(L"version", version.c_str(), ENV_GLOBAL);
|
|
||||||
env_set(L"FISH_VERSION", version.c_str(), ENV_GLOBAL);
|
|
||||||
|
|
||||||
- const env_var_t fishd_dir_wstr = env_get_string(L"FISHD_SOCKET_DIR");
|
|
||||||
const env_var_t user_dir_wstr = env_get_string(L"USER");
|
|
||||||
|
|
||||||
- wchar_t * fishd_dir = fishd_dir_wstr.missing()?NULL:const_cast<wchar_t*>(fishd_dir_wstr.c_str());
|
|
||||||
+ const char * fishd_dir = common_get_runtime_path();
|
|
||||||
+ env_set(L"__fish_runtime_dir", str2wcstring(fishd_dir).c_str(), ENV_GLOBAL);
|
|
||||||
+
|
|
||||||
wchar_t * user_dir = user_dir_wstr.missing()?NULL:const_cast<wchar_t*>(user_dir_wstr.c_str());
|
|
||||||
|
|
||||||
env_universal_init(fishd_dir , user_dir ,
|
|
||||||
diff --git a/env_universal.cpp b/env_universal.cpp
|
|
||||||
index c7d060a..1a97443 100644
|
|
||||||
--- a/env_universal.cpp
|
|
||||||
+++ b/env_universal.cpp
|
|
||||||
@@ -61,7 +61,7 @@ static int get_socket_count = 0;
|
|
||||||
#define DEFAULT_RETRY_COUNT 15
|
|
||||||
#define DEFAULT_RETRY_DELAY 0.2
|
|
||||||
|
|
||||||
-static wchar_t * path;
|
|
||||||
+static const char * path;
|
|
||||||
static wchar_t *user;
|
|
||||||
static void (*start_fishd)();
|
|
||||||
static void (*external_callback)(fish_message_type_t type, const wchar_t *name, const wchar_t *val);
|
|
||||||
@@ -82,48 +82,19 @@ static int try_get_socket_once(void)
|
|
||||||
{
|
|
||||||
int s;
|
|
||||||
|
|
||||||
- wchar_t *wdir;
|
|
||||||
- wchar_t *wuname;
|
|
||||||
- char *dir = 0;
|
|
||||||
-
|
|
||||||
- wdir = path;
|
|
||||||
- wuname = user;
|
|
||||||
-
|
|
||||||
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
|
|
||||||
{
|
|
||||||
wperror(L"socket");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (wdir)
|
|
||||||
- dir = wcs2str(wdir);
|
|
||||||
- else
|
|
||||||
- dir = strdup("/tmp");
|
|
||||||
-
|
|
||||||
- std::string uname;
|
|
||||||
- if (wuname)
|
|
||||||
- {
|
|
||||||
- uname = wcs2string(wuname);
|
|
||||||
- }
|
|
||||||
- else
|
|
||||||
- {
|
|
||||||
- struct passwd *pw = getpwuid(getuid());
|
|
||||||
- if (pw && pw->pw_name)
|
|
||||||
- {
|
|
||||||
- uname = pw->pw_name;
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
std::string name;
|
|
||||||
- name.reserve(strlen(dir) + uname.size() + strlen(SOCK_FILENAME) + 2);
|
|
||||||
- name.append(dir);
|
|
||||||
- name.append("/");
|
|
||||||
+ name.reserve(strlen(path) + strlen(SOCK_FILENAME) + 1);
|
|
||||||
+ name.append(path);
|
|
||||||
+ name.push_back('/');
|
|
||||||
name.append(SOCK_FILENAME);
|
|
||||||
- name.append(uname);
|
|
||||||
-
|
|
||||||
- free(dir);
|
|
||||||
|
|
||||||
- debug(3, L"Connect to socket %s at fd %2", name.c_str(), s);
|
|
||||||
+ debug(3, L"Connect to socket %s at fd %d", name.c_str(), s);
|
|
||||||
|
|
||||||
struct sockaddr_un local = {};
|
|
||||||
local.sun_family = AF_UNIX;
|
|
||||||
@@ -271,7 +242,7 @@ static void reconnect()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
-void env_universal_init(wchar_t * p,
|
|
||||||
+void env_universal_init(const char * p,
|
|
||||||
wchar_t *u,
|
|
||||||
void (*sf)(),
|
|
||||||
void (*cb)(fish_message_type_t type, const wchar_t *name, const wchar_t *val))
|
|
||||||
diff --git a/env_universal.h b/env_universal.h
|
|
||||||
index 4f38fe7..9e6ab85 100644
|
|
||||||
--- a/env_universal.h
|
|
||||||
+++ b/env_universal.h
|
|
||||||
@@ -17,7 +17,7 @@ extern connection_t env_universal_server;
|
|
||||||
/**
|
|
||||||
Initialize the envuni library
|
|
||||||
*/
|
|
||||||
-void env_universal_init(wchar_t * p,
|
|
||||||
+void env_universal_init(const char * p,
|
|
||||||
wchar_t *u,
|
|
||||||
void (*sf)(),
|
|
||||||
void (*cb)(fish_message_type_t type, const wchar_t *name, const wchar_t *val));
|
|
||||||
diff --git a/env_universal_common.cpp b/env_universal_common.cpp
|
|
||||||
index f600e70..2b12cf1 100644
|
|
||||||
--- a/env_universal_common.cpp
|
|
||||||
+++ b/env_universal_common.cpp
|
|
||||||
@@ -27,7 +27,6 @@
|
|
||||||
#include <locale.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <signal.h>
|
|
||||||
-#include <sys/stat.h>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#ifdef HAVE_SYS_SELECT_H
|
|
||||||
@@ -87,6 +86,13 @@
|
|
||||||
#define ENV_UNIVERSAL_EOF 0x102
|
|
||||||
|
|
||||||
/**
|
|
||||||
+ Maximum length of socket filename
|
|
||||||
+*/
|
|
||||||
+#ifndef UNIX_PATH_MAX
|
|
||||||
+#define UNIX_PATH_MAX 100
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+/**
|
|
||||||
A variable entry. Stores the value of a variable and whether it
|
|
||||||
should be exported. Obviously, it needs to be allocated large
|
|
||||||
enough to fit the value string.
|
|
||||||
@@ -417,7 +423,7 @@ void env_universal_common_init(void (*cb)(fish_message_type_t type, const wchar_
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
- Read one byte of date form the specified connection
|
|
||||||
+ Read one byte of date from the specified connection
|
|
||||||
*/
|
|
||||||
static int read_byte(connection_t *src)
|
|
||||||
{
|
|
||||||
diff --git a/env_universal_common.h b/env_universal_common.h
|
|
||||||
index 0a13a41..deddfb3 100644
|
|
||||||
--- a/env_universal_common.h
|
|
||||||
+++ b/env_universal_common.h
|
|
||||||
@@ -33,9 +33,9 @@
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
- The filename to use for univeral variables. The username is appended
|
|
||||||
+ The filename to use for univeral variables.
|
|
||||||
*/
|
|
||||||
-#define SOCK_FILENAME "fishd.socket."
|
|
||||||
+#define SOCK_FILENAME "fishd.socket"
|
|
||||||
|
|
||||||
/**
|
|
||||||
The different types of commands that can be sent between client/server
|
|
||||||
@@ -134,6 +134,11 @@ void try_send_all(connection_t *c);
|
|
||||||
message_t *create_message(fish_message_type_t type, const wchar_t *key, const wchar_t *val);
|
|
||||||
|
|
||||||
/**
|
|
||||||
+ Constructs the fish socket filename
|
|
||||||
+*/
|
|
||||||
+std::string env_universal_common_get_socket_filename(void);
|
|
||||||
+
|
|
||||||
+/**
|
|
||||||
Init the library
|
|
||||||
*/
|
|
||||||
void env_universal_common_init(void (*cb)(fish_message_type_t type, const wchar_t *key, const wchar_t *val));
|
|
||||||
diff --git a/fish_pager.cpp b/fish_pager.cpp
|
|
||||||
index 9cde933..27bc80e 100644
|
|
||||||
--- a/fish_pager.cpp
|
|
||||||
+++ b/fish_pager.cpp
|
|
||||||
@@ -1033,7 +1033,7 @@ static void init(int mangle_descriptors, int out)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
- env_universal_init(0, 0, 0, 0);
|
|
||||||
+ env_universal_init("", 0, 0, 0);
|
|
||||||
input_common_init(&interrupt_handler);
|
|
||||||
output_set_writer(&pager_buffered_writer);
|
|
||||||
|
|
||||||
diff --git a/fishd.cpp b/fishd.cpp
|
|
||||||
index edb79c2..dd43647 100644
|
|
||||||
--- a/fishd.cpp
|
|
||||||
+++ b/fishd.cpp
|
|
||||||
@@ -159,6 +159,27 @@ static int quit=0;
|
|
||||||
*/
|
|
||||||
static std::string get_socket_filename(void)
|
|
||||||
{
|
|
||||||
+ const char *dir = common_get_runtime_path();
|
|
||||||
+
|
|
||||||
+ std::string name;
|
|
||||||
+ name.reserve(strlen(dir) + strlen(SOCK_FILENAME) + 1);
|
|
||||||
+ name.append(dir);
|
|
||||||
+ name.push_back('/');
|
|
||||||
+ name.append(SOCK_FILENAME);
|
|
||||||
+
|
|
||||||
+ if (name.size() >= UNIX_PATH_MAX)
|
|
||||||
+ {
|
|
||||||
+ debug(1, L"Filename too long: '%s'", name.c_str());
|
|
||||||
+ exit(EXIT_FAILURE);
|
|
||||||
+ }
|
|
||||||
+ return name;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/**
|
|
||||||
+ Constructs the legacy socket filename
|
|
||||||
+*/
|
|
||||||
+static std::string get_old_socket_filename(void)
|
|
||||||
+{
|
|
||||||
const char *dir = getenv("FISHD_SOCKET_DIR");
|
|
||||||
char *uname = getenv("USER");
|
|
||||||
|
|
||||||
@@ -174,10 +195,9 @@ static std::string get_socket_filename(void)
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name;
|
|
||||||
- name.reserve(strlen(dir)+ strlen(uname)+ strlen(SOCK_FILENAME) + 1);
|
|
||||||
+ name.reserve(strlen(dir)+ strlen(uname)+ strlen("fishd.socket.") + 1);
|
|
||||||
name.append(dir);
|
|
||||||
- name.push_back('/');
|
|
||||||
- name.append(SOCK_FILENAME);
|
|
||||||
+ name.append("/fishd.socket.");
|
|
||||||
name.append(uname);
|
|
||||||
|
|
||||||
if (name.size() >= UNIX_PATH_MAX)
|
|
||||||
@@ -541,6 +561,7 @@ repeat:
|
|
||||||
int exitcode = EXIT_FAILURE;
|
|
||||||
struct sockaddr_un local;
|
|
||||||
const std::string sock_name = get_socket_filename();
|
|
||||||
+ const std::string old_sock_name = get_old_socket_filename();
|
|
||||||
|
|
||||||
/*
|
|
||||||
Start critical section protected by lock
|
|
||||||
@@ -598,6 +619,19 @@ repeat:
|
|
||||||
doexit = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // Attempt to hardlink the old socket name so that old versions of fish keep working on upgrade
|
|
||||||
+ // Not critical if it fails
|
|
||||||
+ if (unlink(old_sock_name.c_str()) != 0 && errno != ENOENT)
|
|
||||||
+ {
|
|
||||||
+ debug(0, L"Could not create legacy socket path");
|
|
||||||
+ wperror(L"unlink");
|
|
||||||
+ }
|
|
||||||
+ else if (link(sock_name.c_str(), old_sock_name.c_str()) != 0)
|
|
||||||
+ {
|
|
||||||
+ debug(0, L"Could not create legacy socket path");
|
|
||||||
+ wperror(L"link");
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
unlock:
|
|
||||||
(void)unlink(lockfile.c_str());
|
|
||||||
debug(4, L"Released lockfile: %s", lockfile.c_str());
|
|
||||||
@@ -873,6 +907,18 @@ static void init()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
+ Clean up behind ourselves
|
|
||||||
+*/
|
|
||||||
+static void cleanup()
|
|
||||||
+{
|
|
||||||
+ if (unlink(get_old_socket_filename().c_str()) != 0)
|
|
||||||
+ {
|
|
||||||
+ debug(0, L"Could not remove legacy socket path");
|
|
||||||
+ wperror(L"unlink");
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/**
|
|
||||||
Main function for fishd
|
|
||||||
*/
|
|
||||||
int main(int argc, char ** argv)
|
|
||||||
@@ -973,6 +1019,7 @@ int main(int argc, char ** argv)
|
|
||||||
if (quit)
|
|
||||||
{
|
|
||||||
save();
|
|
||||||
+ cleanup();
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -982,6 +1029,7 @@ int main(int argc, char ** argv)
|
|
||||||
if (errno != EINTR)
|
|
||||||
{
|
|
||||||
wperror(L"select");
|
|
||||||
+ cleanup();
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -994,6 +1042,7 @@ int main(int argc, char ** argv)
|
|
||||||
&t)) == -1)
|
|
||||||
{
|
|
||||||
wperror(L"accept");
|
|
||||||
+ cleanup();
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
@@ -1070,6 +1119,7 @@ int main(int argc, char ** argv)
|
|
||||||
{
|
|
||||||
debug(0, L"No more clients. Quitting");
|
|
||||||
save();
|
|
||||||
+ cleanup();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
--
|
|
||||||
1.9.3
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
|||||||
From c0989dce2d882c94eb3183e7b94402ba53534abb Mon Sep 17 00:00:00 2001
|
|
||||||
Message-Id: <c0989dce2d882c94eb3183e7b94402ba53534abb.1398703637.git.luto@amacapital.net>
|
|
||||||
In-Reply-To: <3c5d5b344ee945b99e4bb16a44af6f293601813d.1398703637.git.luto@amacapital.net>
|
|
||||||
References: <3c5d5b344ee945b99e4bb16a44af6f293601813d.1398703637.git.luto@amacapital.net>
|
|
||||||
From: David Adam <zanchey@ucc.gu.uwa.edu.au>
|
|
||||||
Date: Sun, 20 Apr 2014 23:51:20 +0800
|
|
||||||
Subject: [PATCH 4/4] use mktemp(1) to generate temporary file names
|
|
||||||
|
|
||||||
Fix for CVE-2014-2906.
|
|
||||||
|
|
||||||
Closes a race condition in funced which would allow execution of
|
|
||||||
arbitrary code; closes a race condition in psub which would allow
|
|
||||||
alternation of the data stream.
|
|
||||||
|
|
||||||
Note that `psub -f` does not work (#1040); a fix should be committed
|
|
||||||
separately for ease of maintenance.
|
|
||||||
---
|
|
||||||
share/functions/funced.fish | 6 +-----
|
|
||||||
share/functions/psub.fish | 11 +++--------
|
|
||||||
2 files changed, 4 insertions(+), 13 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/share/functions/funced.fish b/share/functions/funced.fish
|
|
||||||
index 3c2de06..ca2e277 100644
|
|
||||||
--- a/share/functions/funced.fish
|
|
||||||
+++ b/share/functions/funced.fish
|
|
||||||
@@ -81,11 +81,7 @@ function funced --description 'Edit function definition'
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
- set -q TMPDIR; or set -l TMPDIR /tmp
|
|
||||||
- set -l tmpname (printf "$TMPDIR/fish_funced_%d_%d.fish" %self (random))
|
|
||||||
- while test -f $tmpname
|
|
||||||
- set tmpname (printf "$TMPDIR/fish_funced_%d_%d.fish" %self (random))
|
|
||||||
- end
|
|
||||||
+ set tmpname (mktemp -t fish_funced.XXXXXXXXXX)
|
|
||||||
|
|
||||||
if functions -q -- $funcname
|
|
||||||
functions -- $funcname > $tmpname
|
|
||||||
diff --git a/share/functions/psub.fish b/share/functions/psub.fish
|
|
||||||
index 42e34c7..7877aa4 100644
|
|
||||||
--- a/share/functions/psub.fish
|
|
||||||
+++ b/share/functions/psub.fish
|
|
||||||
@@ -45,21 +45,16 @@ function psub --description "Read from stdin into a file and output the filename
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
- # Find unique file name for writing output to
|
|
||||||
- while true
|
|
||||||
- set filename /tmp/.psub.(echo %self).(random);
|
|
||||||
- if not test -e $filename
|
|
||||||
- break;
|
|
||||||
- end
|
|
||||||
- end
|
|
||||||
-
|
|
||||||
if test use_fifo = 1
|
|
||||||
# Write output to pipe. This needs to be done in the background so
|
|
||||||
# that the command substitution exits without needing to wait for
|
|
||||||
# all the commands to exit
|
|
||||||
+ set dir (mktemp -d /tmp/.psub.XXXXXXXXXX); or return
|
|
||||||
+ set filename $dir/psub.fifo
|
|
||||||
mkfifo $filename
|
|
||||||
cat >$filename &
|
|
||||||
else
|
|
||||||
+ set filename (mktemp /tmp/.psub.XXXXXXXXXX)
|
|
||||||
cat >$filename
|
|
||||||
end
|
|
||||||
|
|
||||||
--
|
|
||||||
1.9.0
|
|
||||||
|
|
@ -1,239 +0,0 @@
|
|||||||
commit 397249a8d5a939d044da8ecfbb1654d48ce5a153
|
|
||||||
Author: David Adam <zanchey@ucc.gu.uwa.edu.au>
|
|
||||||
Date: Mon Aug 4 13:34:26 2014 +0800
|
|
||||||
|
|
||||||
Authenticate connections to web_config service
|
|
||||||
|
|
||||||
- Require all requests to use a session path.
|
|
||||||
- Use a redirect file to avoid exposing the URL on the command line, as
|
|
||||||
it contains the session path.
|
|
||||||
|
|
||||||
Fix for CVE-2014-2914.
|
|
||||||
Closes #1438.
|
|
||||||
|
|
||||||
diff --git a/share/tools/web_config/index.html b/share/tools/web_config/index.html
|
|
||||||
index 22cd470..90df114 100644
|
|
||||||
--- a/share/tools/web_config/index.html
|
|
||||||
+++ b/share/tools/web_config/index.html
|
|
||||||
@@ -556,7 +556,7 @@ function switch_tab(new_tab) {
|
|
||||||
if (new_tab == 'tab_colors') {
|
|
||||||
/* Keep track of whether this is the first element */
|
|
||||||
var first = true
|
|
||||||
- run_get_request('/colors/', function(key_and_values){
|
|
||||||
+ run_get_request('colors/', function(key_and_values){
|
|
||||||
/* Result is name, description, value */
|
|
||||||
var key = key_and_values[0]
|
|
||||||
var description = key_and_values[1]
|
|
||||||
@@ -577,7 +577,7 @@ function switch_tab(new_tab) {
|
|
||||||
sample_prompts.length = 0
|
|
||||||
/* Color the first one blue */
|
|
||||||
var first = true;
|
|
||||||
- run_get_request('/sample_prompts/', function(sample_prompt){
|
|
||||||
+ run_get_request('sample_prompts/', function(sample_prompt){
|
|
||||||
var name = sample_prompt['name']
|
|
||||||
sample_prompts[name] = sample_prompt
|
|
||||||
var color = first ? '66F' : 'AAA'
|
|
||||||
@@ -594,7 +594,7 @@ function switch_tab(new_tab) {
|
|
||||||
} else if (new_tab == 'tab_functions') {
|
|
||||||
/* Keep track of whether this is the first element */
|
|
||||||
var first = true
|
|
||||||
- run_get_request('/functions/', function(contents){
|
|
||||||
+ run_get_request('functions/', function(contents){
|
|
||||||
var elem = create_master_element(contents, false/* description */, 'AAAAAA', '11pt', select_function_master_element)
|
|
||||||
if (first) {
|
|
||||||
/* It's the first element, so select it, so something gets selected */
|
|
||||||
@@ -606,7 +606,7 @@ function switch_tab(new_tab) {
|
|
||||||
$('#master_detail_table').show()
|
|
||||||
wants_data_table = false
|
|
||||||
} else if (new_tab == 'tab_variables') {
|
|
||||||
- run_get_request_with_bulk_handler('/variables/', function(json_contents){
|
|
||||||
+ run_get_request_with_bulk_handler('variables/', function(json_contents){
|
|
||||||
var rows = new Array()
|
|
||||||
for (var i = 0; i < json_contents.length; i++) {
|
|
||||||
var contents = json_contents[i]
|
|
||||||
@@ -622,7 +622,7 @@ function switch_tab(new_tab) {
|
|
||||||
} else if (new_tab == 'tab_history') {
|
|
||||||
// Clear the history map
|
|
||||||
history_element_map.length = 0
|
|
||||||
- run_get_request_with_bulk_handler('/history/', function(json_contents){
|
|
||||||
+ run_get_request_with_bulk_handler('history/', function(json_contents){
|
|
||||||
start = new Date().getTime()
|
|
||||||
var rows = new Array()
|
|
||||||
for (var i = 0; i < json_contents.length; i++) {
|
|
||||||
@@ -757,7 +757,7 @@ function select_color_master_element(elem) {
|
|
||||||
function select_function_master_element(elem) {
|
|
||||||
select_master_element(elem)
|
|
||||||
|
|
||||||
- run_post_request('/get_function/', {
|
|
||||||
+ run_post_request('get_function/', {
|
|
||||||
what: current_master_element_name()
|
|
||||||
}, function(contents){
|
|
||||||
/* Replace leading tabs and groups of four spaces at the beginning of a line with two spaces. */
|
|
||||||
@@ -773,7 +773,7 @@ function select_sample_prompt_master_element(elem) {
|
|
||||||
select_master_element(elem)
|
|
||||||
var name = current_master_element_name()
|
|
||||||
sample_prompt = sample_prompts[name]
|
|
||||||
- run_post_request('/get_sample_prompt/', {
|
|
||||||
+ run_post_request('get_sample_prompt/', {
|
|
||||||
what: sample_prompt['function']
|
|
||||||
}, function(keys_and_values){
|
|
||||||
var prompt_func = keys_and_values['function']
|
|
||||||
@@ -788,7 +788,7 @@ function select_sample_prompt_master_element(elem) {
|
|
||||||
function select_current_prompt_master_element(elem) {
|
|
||||||
$('.prompt_save_button').hide()
|
|
||||||
select_master_element(elem)
|
|
||||||
- run_get_request_with_bulk_handler('/current_prompt/', function(keys_and_values){
|
|
||||||
+ run_get_request_with_bulk_handler('current_prompt/', function(keys_and_values){
|
|
||||||
var prompt_func = keys_and_values['function']
|
|
||||||
var prompt_demo = keys_and_values['demo']
|
|
||||||
var prompt_font_size = keys_and_values['font_size']
|
|
||||||
@@ -801,7 +801,7 @@ function select_current_prompt_master_element(elem) {
|
|
||||||
function save_current_prompt() {
|
|
||||||
var name = current_master_element_name()
|
|
||||||
var sample_prompt = sample_prompts[name]
|
|
||||||
- run_post_request('/set_prompt/', {
|
|
||||||
+ run_post_request('set_prompt/', {
|
|
||||||
what: sample_prompt['function']
|
|
||||||
}, function(contents){
|
|
||||||
if (contents == "OK") {
|
|
||||||
@@ -817,7 +817,7 @@ function post_style_to_server() {
|
|
||||||
if (! style)
|
|
||||||
return
|
|
||||||
|
|
||||||
- run_post_request('/set_color/', {
|
|
||||||
+ run_post_request('set_color/', {
|
|
||||||
what: current_master_element_name(),
|
|
||||||
color: style.color,
|
|
||||||
background_color: style.background_color,
|
|
||||||
@@ -1221,7 +1221,7 @@ function escape_HTML(foo) {
|
|
||||||
function tell_fish_to_delete_element(idx) {
|
|
||||||
var row_elem = $('#data_table_row_' + idx)
|
|
||||||
var txt = history_element_map[idx]
|
|
||||||
- run_post_request('/delete_history_item/', {
|
|
||||||
+ run_post_request('delete_history_item/', {
|
|
||||||
what: txt
|
|
||||||
}, function(contents){
|
|
||||||
if (contents == "OK") {
|
|
||||||
diff --git a/share/tools/web_config/webconfig.py b/share/tools/web_config/webconfig.py
|
|
||||||
index 1b9250b..2a103eb 100755
|
|
||||||
--- a/share/tools/web_config/webconfig.py
|
|
||||||
+++ b/share/tools/web_config/webconfig.py
|
|
||||||
@@ -17,7 +17,7 @@ else:
|
|
||||||
from urllib.parse import parse_qs
|
|
||||||
import webbrowser
|
|
||||||
import subprocess
|
|
||||||
-import re, socket, os, sys, cgi, select, time, glob
|
|
||||||
+import re, socket, os, sys, cgi, select, time, glob, random, string
|
|
||||||
try:
|
|
||||||
import json
|
|
||||||
except ImportError:
|
|
||||||
@@ -485,9 +485,16 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|
||||||
else: font_size = '18pt'
|
|
||||||
return font_size
|
|
||||||
|
|
||||||
-
|
|
||||||
def do_GET(self):
|
|
||||||
p = self.path
|
|
||||||
+
|
|
||||||
+ authpath = '/' + authkey
|
|
||||||
+ if p.startswith(authpath):
|
|
||||||
+ p = p[len(authpath):]
|
|
||||||
+ else:
|
|
||||||
+ return self.send_error(403)
|
|
||||||
+ self.path = p
|
|
||||||
+
|
|
||||||
if p == '/colors/':
|
|
||||||
output = self.do_get_colors()
|
|
||||||
elif p == '/functions/':
|
|
||||||
@@ -519,6 +526,14 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|
||||||
|
|
||||||
def do_POST(self):
|
|
||||||
p = self.path
|
|
||||||
+
|
|
||||||
+ authpath = '/' + authkey
|
|
||||||
+ if p.startswith(authpath):
|
|
||||||
+ p = p[len(authpath):]
|
|
||||||
+ else:
|
|
||||||
+ return self.send_error(403)
|
|
||||||
+ self.path = p
|
|
||||||
+
|
|
||||||
if IS_PY2:
|
|
||||||
ctype, pdict = cgi.parse_header(self.headers.getheader('content-type'))
|
|
||||||
else: # Python 3
|
|
||||||
@@ -582,7 +597,19 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|
||||||
def log_request(self, code='-', size='-'):
|
|
||||||
""" Disable request logging """
|
|
||||||
pass
|
|
||||||
-
|
|
||||||
+
|
|
||||||
+redirect_template_html = """
|
|
||||||
+<!DOCTYPE html>
|
|
||||||
+<html>
|
|
||||||
+ <head>
|
|
||||||
+ <meta http-equiv="refresh" content="0;URL='%s'" />
|
|
||||||
+ </head>
|
|
||||||
+ <body>
|
|
||||||
+ <p><a href="%s">Start the Fish Web config</a></p>
|
|
||||||
+ </body>
|
|
||||||
+</html>
|
|
||||||
+"""
|
|
||||||
+
|
|
||||||
# find fish
|
|
||||||
fish_bin_dir = os.environ.get('__fish_bin_dir')
|
|
||||||
fish_bin_path = None
|
|
||||||
@@ -618,6 +645,9 @@ initial_wd = os.getcwd()
|
|
||||||
where = os.path.dirname(sys.argv[0])
|
|
||||||
os.chdir(where)
|
|
||||||
|
|
||||||
+# Generate a 16-byte random key as a hexadecimal string
|
|
||||||
+authkey = hex(random.getrandbits(16*4))[2:]
|
|
||||||
+
|
|
||||||
# Try to find a suitable port
|
|
||||||
PORT = 8000
|
|
||||||
while PORT <= 9000:
|
|
||||||
@@ -647,9 +677,36 @@ if len(sys.argv) > 1:
|
|
||||||
initial_tab = '#' + tab
|
|
||||||
break
|
|
||||||
|
|
||||||
-url = 'http://localhost:%d/%s' % (PORT, initial_tab)
|
|
||||||
-print("Web config started at '%s'. Hit enter to stop." % url)
|
|
||||||
-webbrowser.open(url)
|
|
||||||
+url = 'http://localhost:%d/%s/%s' % (PORT, authkey, initial_tab)
|
|
||||||
+
|
|
||||||
+# Create temporary file to hold redirect to real server
|
|
||||||
+# This prevents exposing the URL containing the authentication key on the command line
|
|
||||||
+# (see CVE-2014-2914 or https://github.com/fish-shell/fish-shell/issues/1438)
|
|
||||||
+if 'XDG_CACHE_HOME' in os.environ:
|
|
||||||
+ dirname = os.path.expanduser(os.path.expandvars('$XDG_CACHE_HOME/fish/'))
|
|
||||||
+else:
|
|
||||||
+ dirname = os.path.expanduser('~/.cache/fish/')
|
|
||||||
+
|
|
||||||
+os.umask(0o0077)
|
|
||||||
+try:
|
|
||||||
+ os.makedirs(dirname, 0o0700)
|
|
||||||
+except OSError as e:
|
|
||||||
+ if e.errno == 17:
|
|
||||||
+ pass
|
|
||||||
+ else:
|
|
||||||
+ raise e
|
|
||||||
+
|
|
||||||
+randtoken = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6))
|
|
||||||
+filename = dirname + 'web_config-%s.html' % randtoken
|
|
||||||
+
|
|
||||||
+f = open(filename, 'w')
|
|
||||||
+f.write(redirect_template_html % (url, url))
|
|
||||||
+f.close()
|
|
||||||
+
|
|
||||||
+# Open temporary file as URL
|
|
||||||
+fileurl = 'file://' + filename
|
|
||||||
+print("Web config started at '%s'. Hit enter to stop." % fileurl)
|
|
||||||
+webbrowser.open(fileurl)
|
|
||||||
|
|
||||||
# Select on stdin and httpd
|
|
||||||
stdin_no = sys.stdin.fileno()
|
|
||||||
@@ -666,3 +723,5 @@ try:
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print("\nShutting down.")
|
|
||||||
|
|
||||||
+# Clean up temporary file
|
|
||||||
+os.remove(filename)
|
|
@ -1,47 +0,0 @@
|
|||||||
From 10642a34f17ae45bd93be3ae6021ee920d3da0c2 Mon Sep 17 00:00:00 2001
|
|
||||||
Message-Id: <10642a34f17ae45bd93be3ae6021ee920d3da0c2.1398707555.git.luto@amacapital.net>
|
|
||||||
In-Reply-To: <3c5d5b344ee945b99e4bb16a44af6f293601813d.1398707555.git.luto@amacapital.net>
|
|
||||||
References: <3c5d5b344ee945b99e4bb16a44af6f293601813d.1398707555.git.luto@amacapital.net>
|
|
||||||
From: Anders Bergh <anders1@gmail.com>
|
|
||||||
Date: Tue, 4 Mar 2014 09:59:26 +0100
|
|
||||||
Subject: [PATCH 2/4] fish_config: Listen on both IPv6 and IPv4.
|
|
||||||
|
|
||||||
A subclass of TCPServer was created to deny any non-local connections and to
|
|
||||||
listen using an IPv6 socket.
|
|
||||||
---
|
|
||||||
share/tools/web_config/webconfig.py | 12 +++++++++++-
|
|
||||||
1 file changed, 11 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/share/tools/web_config/webconfig.py b/share/tools/web_config/webconfig.py
|
|
||||||
index f735a02..1b9250b 100755
|
|
||||||
--- a/share/tools/web_config/webconfig.py
|
|
||||||
+++ b/share/tools/web_config/webconfig.py
|
|
||||||
@@ -250,6 +250,16 @@ class FishVar:
|
|
||||||
if self.exported: flags.append('exported')
|
|
||||||
return [self.name, self.value, ', '.join(flags)]
|
|
||||||
|
|
||||||
+class FishConfigTCPServer(SocketServer.TCPServer):
|
|
||||||
+ """TCPServer that only accepts connections from localhost (IPv4/IPv6)."""
|
|
||||||
+ WHITELIST = set(['::1', '::ffff:127.0.0.1', '127.0.0.1'])
|
|
||||||
+
|
|
||||||
+ address_family = socket.AF_INET6
|
|
||||||
+
|
|
||||||
+ def verify_request(self, request, client_address):
|
|
||||||
+ return client_address[0] in FishConfigTCPServer.WHITELIST
|
|
||||||
+
|
|
||||||
+
|
|
||||||
class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|
||||||
|
|
||||||
def write_to_wfile(self, txt):
|
|
||||||
@@ -613,7 +623,7 @@ PORT = 8000
|
|
||||||
while PORT <= 9000:
|
|
||||||
try:
|
|
||||||
Handler = FishConfigHTTPRequestHandler
|
|
||||||
- httpd = SocketServer.TCPServer(("", PORT), Handler)
|
|
||||||
+ httpd = FishConfigTCPServer(("::", PORT), Handler)
|
|
||||||
# Success
|
|
||||||
break
|
|
||||||
except socket.error:
|
|
||||||
--
|
|
||||||
1.9.0
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
|||||||
commit 78e2b7cc0897de3eb2a8cdc0f5efe49a34402f9d
|
|
||||||
Author: Andy Lutomirski <luto@amacapital.net>
|
|
||||||
Date: Mon Aug 11 17:50:56 2014 -0700
|
|
||||||
|
|
||||||
webconfig: Use a constant-time token comparison
|
|
||||||
|
|
||||||
This prevents a linear-time attack to recover the auth token.
|
|
||||||
|
|
||||||
diff --git a/share/tools/web_config/webconfig.py b/share/tools/web_config/webconfig.py
|
|
||||||
index 2a103eb..452f771 100755
|
|
||||||
--- a/share/tools/web_config/webconfig.py
|
|
||||||
+++ b/share/tools/web_config/webconfig.py
|
|
||||||
@@ -471,6 +471,14 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|
||||||
# Ignore unreadable files, etc
|
|
||||||
pass
|
|
||||||
return result
|
|
||||||
+
|
|
||||||
+ def secure_startswith(self, haystack, needle):
|
|
||||||
+ if len(haystack) < len(needle):
|
|
||||||
+ return False
|
|
||||||
+ bits = 0
|
|
||||||
+ for x,y in zip(haystack, needle):
|
|
||||||
+ bits |= ord(x) ^ ord(y)
|
|
||||||
+ return bits == 0
|
|
||||||
|
|
||||||
def font_size_for_ansi_prompt(self, prompt_demo_ansi):
|
|
||||||
width = ansi_prompt_line_width(prompt_demo_ansi)
|
|
||||||
@@ -489,7 +497,7 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|
||||||
p = self.path
|
|
||||||
|
|
||||||
authpath = '/' + authkey
|
|
||||||
- if p.startswith(authpath):
|
|
||||||
+ if self.secure_startswith(p, authpath):
|
|
||||||
p = p[len(authpath):]
|
|
||||||
else:
|
|
||||||
return self.send_error(403)
|
|
||||||
@@ -528,7 +536,7 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|
||||||
p = self.path
|
|
||||||
|
|
||||||
authpath = '/' + authkey
|
|
||||||
- if p.startswith(authpath):
|
|
||||||
+ if self.secure_startswith(p, authpath):
|
|
||||||
p = p[len(authpath):]
|
|
||||||
else:
|
|
||||||
return self.send_error(403)
|
|
@ -1,19 +0,0 @@
|
|||||||
commit 236a0ce46819ce4b93f73ba112e3bfb0726bade7
|
|
||||||
Author: Andy Lutomirski <luto@amacapital.net>
|
|
||||||
Date: Mon Aug 11 17:51:27 2014 -0700
|
|
||||||
|
|
||||||
webconfig: Use 16 byte tokens, as advertized
|
|
||||||
|
|
||||||
diff --git a/share/tools/web_config/webconfig.py b/share/tools/web_config/webconfig.py
|
|
||||||
index e129c76..2ceb67e 100755
|
|
||||||
--- a/share/tools/web_config/webconfig.py
|
|
||||||
+++ b/share/tools/web_config/webconfig.py
|
|
||||||
@@ -654,7 +654,7 @@ where = os.path.dirname(sys.argv[0])
|
|
||||||
os.chdir(where)
|
|
||||||
|
|
||||||
# Generate a 16-byte random key as a hexadecimal string
|
|
||||||
-authkey = hex(random.getrandbits(16*4))[2:]
|
|
||||||
+authkey = hex(random.getrandbits(16*8))[2:]
|
|
||||||
|
|
||||||
# Try to find a suitable port
|
|
||||||
PORT = 8000
|
|
@ -1,21 +0,0 @@
|
|||||||
commit f5d81d3beac2542d675af15bf7f71762c456f30d
|
|
||||||
Author: Andy Lutomirski <luto@amacapital.net>
|
|
||||||
Date: Mon Aug 11 17:52:27 2014 -0700
|
|
||||||
|
|
||||||
webconfig: Get the auth token from os.urandom
|
|
||||||
|
|
||||||
random.getrandbits shouldn't be used for security.
|
|
||||||
|
|
||||||
diff --git a/share/tools/web_config/webconfig.py b/share/tools/web_config/webconfig.py
|
|
||||||
index 2ceb67e..f36f63f 100755
|
|
||||||
--- a/share/tools/web_config/webconfig.py
|
|
||||||
+++ b/share/tools/web_config/webconfig.py
|
|
||||||
@@ -654,7 +654,7 @@ where = os.path.dirname(sys.argv[0])
|
|
||||||
os.chdir(where)
|
|
||||||
|
|
||||||
# Generate a 16-byte random key as a hexadecimal string
|
|
||||||
-authkey = hex(random.getrandbits(16*8))[2:]
|
|
||||||
+authkey = hex(os.urandom(16))[2:]
|
|
||||||
|
|
||||||
# Try to find a suitable port
|
|
||||||
PORT = 8000
|
|
@ -1,28 +0,0 @@
|
|||||||
commit a7f1e81e6ac23fe4b6fd86023681e2975703078d
|
|
||||||
Author: Andy Lutomirski <luto@amacapital.net>
|
|
||||||
Date: Mon Aug 11 18:18:21 2014 -0700
|
|
||||||
|
|
||||||
webconfig: Convert authkey to hex correctly
|
|
||||||
|
|
||||||
diff --git a/share/tools/web_config/webconfig.py b/share/tools/web_config/webconfig.py
|
|
||||||
index 5c7d2b9..43d2ced 100755
|
|
||||||
--- a/share/tools/web_config/webconfig.py
|
|
||||||
+++ b/share/tools/web_config/webconfig.py
|
|
||||||
@@ -17,7 +17,7 @@ else:
|
|
||||||
from urllib.parse import parse_qs
|
|
||||||
import webbrowser
|
|
||||||
import subprocess
|
|
||||||
-import re, socket, os, sys, cgi, select, time, glob, random, string
|
|
||||||
+import re, socket, os, sys, cgi, select, time, glob, random, string, binascii
|
|
||||||
try:
|
|
||||||
import json
|
|
||||||
except ImportError:
|
|
||||||
@@ -654,7 +654,7 @@ where = os.path.dirname(sys.argv[0])
|
|
||||||
os.chdir(where)
|
|
||||||
|
|
||||||
# Generate a 16-byte random key as a hexadecimal string
|
|
||||||
-authkey = hex(os.urandom(16))[2:]
|
|
||||||
+authkey = binascii.b2a_hex(os.urandom(16))
|
|
||||||
|
|
||||||
# Try to find a suitable port
|
|
||||||
PORT = 8000
|
|
Loading…
Reference in new issue