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);