diff --git a/pkg/static/login.html b/pkg/static/login.html
index d91201916952..3740f0a7e490 100644
--- a/pkg/static/login.html
+++ b/pkg/static/login.html
@@ -21,6 +21,14 @@
+
+
diff --git a/pkg/static/login.js b/pkg/static/login.js
index 37481144381e..7524dc6d4c17 100644
--- a/pkg/static/login.js
+++ b/pkg/static/login.js
@@ -338,6 +338,33 @@ import "./login.scss";
event.stopPropagation();
}
+ function deal_with_multihost() {
+ // If we are currently logged in to some machine, but still
+ // end up on the login page, we are about to load resources
+ // from two machines into the same browser origin.
+
+ const logged_into = environment["logged-into"];
+ const cur_machine = logged_into.length > 0 ? logged_into[0] : null;
+
+ function redirect_to_current_machine() {
+ if (cur_machine === ".")
+ login_reload("/");
+ else
+ login_reload("/=" + cur_machine);
+ }
+
+ if (cur_machine) {
+ if (!environment.page.allow_multi_host)
+ redirect_to_current_machine();
+ else {
+ id("multihost-message").textContent = format(_("You are already connected to '$0' in this browser session. Connecting to other hosts will allow them to execute arbitrary code on each other. Please be careful."),
+ cur_machine == "." ? "localhost" : cur_machine);
+ id("multihost-get-me-there").addEventListener("click", redirect_to_current_machine);
+ show('#multihost-warning');
+ }
+ }
+ }
+
function boot() {
window.onload = null;
@@ -348,6 +375,8 @@ import "./login.scss";
document.documentElement.dir = window.cockpit_po[""]["language-direction"];
}
+ deal_with_multihost();
+
setup_path_globals(window.location.pathname);
/* Determine if we are nested or not, and switch styles */
@@ -948,6 +977,8 @@ import "./login.scss";
}
function login_reload (wanted) {
+ console.log("RELOAD", wanted);
+
// Force a reload if not triggered below
// because only the hash part of the url
// changed
diff --git a/pkg/static/login.scss b/pkg/static/login.scss
index 33e664562fa9..b1fddb29d11f 100644
--- a/pkg/static/login.scss
+++ b/pkg/static/login.scss
@@ -354,14 +354,14 @@ label.checkbox {
display: none;
}
-.login-pf #banner {
+.login-pf #banner, .login-pf #multihost-warning {
margin-block: 1rem 0.5rem;
margin-inline: 0;
grid-area: banner;
inline-size: 100%;
}
-#banner-message {
+#banner-message, #multihost-message {
white-space: pre-wrap;
max-block-size: 12em;
overflow: auto;
diff --git a/src/ws/cockpitauth.c b/src/ws/cockpitauth.c
index 99f5c33ab2c6..f47beee377b9 100644
--- a/src/ws/cockpitauth.c
+++ b/src/ws/cockpitauth.c
@@ -1706,3 +1706,13 @@ cockpit_auth_empty_cookie_value (const gchar *path, gboolean secure)
return cookie_line;
}
+
+gchar *
+cockpit_auth_cookie_name (const gchar *path)
+{
+ gchar *application = cockpit_auth_parse_application (path, NULL);
+ gchar *cookie = application_cookie_name (application);
+ g_free (application);
+
+ return cookie;
+}
diff --git a/src/ws/cockpitauth.h b/src/ws/cockpitauth.h
index 038d5a294c73..394414de848a 100644
--- a/src/ws/cockpitauth.h
+++ b/src/ws/cockpitauth.h
@@ -108,6 +108,8 @@ gchar * cockpit_auth_parse_application (const gchar *path,
gchar * cockpit_auth_empty_cookie_value (const gchar *path,
gboolean secure);
+gchar * cockpit_auth_cookie_name (const gchar *path);
+
G_END_DECLS
#endif
diff --git a/src/ws/cockpithandlers.c b/src/ws/cockpithandlers.c
index 29bb690cdf1a..686f4a201f32 100644
--- a/src/ws/cockpithandlers.c
+++ b/src/ws/cockpithandlers.c
@@ -277,8 +277,48 @@ add_page_to_environment (JsonObject *object,
json_object_set_object_member (object, "page", page);
}
+static void
+add_logged_into_to_environment (JsonObject *object,
+ const gchar *path,
+ GHashTable *request_headers)
+{
+ gchar *h = g_hash_table_lookup (request_headers, "Cookie");
+ if (!h)
+ return;
+
+ g_autofree gchar *self_cookie = cockpit_auth_cookie_name (path);
+
+ JsonArray *logged_into = json_array_new ();
+
+ while (*h) {
+ const gchar *start = h;
+ while (*h && *h != '=')
+ h++;
+ const gchar *equal = h;
+ while (*h && *h != ';')
+ h++;
+ if (*h)
+ h++;
+ while (*h && *h == ' ')
+ h++;
+
+ if (g_str_has_prefix (equal, "=deleted"))
+ continue;
+
+ g_autofree gchar *name = g_strndup (start, equal - start);
+ if (g_str_equal (name, self_cookie))
+ ;
+ else if (g_str_equal (name, "cockpit"))
+ json_array_add_string_element(logged_into, ".");
+ else if (g_str_has_prefix (name, "machine-cockpit+"))
+ json_array_add_string_element(logged_into, name + strlen("machine-cockpit+"));
+ }
+
+ json_object_set_array_member (object, "logged-into", logged_into);
+}
+
static GBytes *
-build_environment (GHashTable *os_release)
+build_environment (GHashTable *os_release, const gchar *path, GHashTable *request_headers)
{
/*
* We don't include entirety of os-release into the
@@ -310,6 +350,7 @@ build_environment (GHashTable *os_release)
json_object_set_boolean_member (object, "is_cockpit_client", is_cockpit_client);
add_page_to_environment (object, is_cockpit_client);
+ add_logged_into_to_environment (object, path, request_headers);
hostname = g_malloc0 (HOST_NAME_MAX + 1);
gethostname (hostname, HOST_NAME_MAX);
@@ -386,7 +427,7 @@ send_login_html (CockpitWebResponse *response,
GBytes *po_bytes;
CockpitWebFilter *filter3 = NULL;
- environment = build_environment (ws->os_release);
+ environment = build_environment (ws->os_release, path, headers);
filter = cockpit_web_inject_new (marker, environment, 1);
g_bytes_unref (environment);
cockpit_web_response_add_filter (response, filter);
@@ -455,6 +496,7 @@ send_login_html (CockpitWebResponse *response,
"Content-Security-Policy", content_security_policy,
"Set-Cookie", cookie_line,
NULL);
+ cockpit_web_response_set_cache_type (response, COCKPIT_WEB_RESPONSE_NO_CACHE);
if (cockpit_web_response_queue (response, bytes))
cockpit_web_response_complete (response);