gboolean cockpit_handler_deauthorize (CockpitWebServer *server, CockpitWebServerRequestType reqtype, const gchar *path, GHashTable *headers, GBytes *input, CockpitWebResponse *response, CockpitHandlerData *ws) { CockpitWebService *service; CockpitCreds *creds; const gchar *body; GBytes *bytes; service = cockpit_auth_check_cookie (ws->auth, headers); if (!service) { cockpit_web_response_error (response, 401, NULL, "Unauthorized"); return TRUE; } /* Poison the creds, so they no longer work for new reauthorization */ creds = cockpit_web_service_get_creds (service); cockpit_creds_poison (creds); g_object_unref (service); body ="<html><head><title>Deauthorized</title></head>" "<body>Deauthorized</body></html>"; bytes = g_bytes_new_static (body, strlen (body)); cockpit_web_response_content (response, NULL, bytes, NULL); g_bytes_unref (bytes); return TRUE; }
static void handle_login (CockpitHandlerData *data, CockpitWebService *service, const gchar *path, GHashTable *headers, CockpitWebResponse *response) { GHashTable *out_headers; GIOStream *io_stream; CockpitCreds *creds; JsonObject *creds_json = NULL; if (service) { out_headers = cockpit_web_server_new_table (); creds = cockpit_web_service_get_creds (service); creds_json = cockpit_creds_to_json (creds); send_login_response (response, creds_json, out_headers); g_hash_table_unref (out_headers); json_object_unref (creds_json); return; } io_stream = cockpit_web_response_get_stream (response); cockpit_auth_login_async (data->auth, path,io_stream, headers, on_login_complete, g_object_ref (response)); }
gboolean cockpit_handler_login (CockpitWebServer *server, const gchar *path, GHashTable *headers, CockpitWebResponse *response, CockpitHandlerData *ws) { CockpitWebService *service; CockpitCreds *creds; gchar *remote_peer = NULL; GHashTable *out_headers; GIOStream *io_stream; service = cockpit_auth_check_cookie (ws->auth, headers); if (service == NULL) { io_stream = cockpit_web_response_get_stream (response); remote_peer = get_remote_address (io_stream); cockpit_auth_login_async (ws->auth, headers, remote_peer, on_login_complete, g_object_ref (response)); g_free (remote_peer); } else { out_headers = cockpit_web_server_new_table (); creds = cockpit_web_service_get_creds (service); send_login_response (response, creds, out_headers); g_hash_table_unref (out_headers); g_object_unref (service); } /* no response yet */ return TRUE; }
static void on_login_complete (GObject *object, GAsyncResult *result, gpointer user_data) { CockpitWebResponse *response = user_data; GError *error = NULL; CockpitWebService *service; CockpitAuthFlags flags = 0; CockpitCreds *creds; GHashTable *headers; GIOStream *io_stream; io_stream = cockpit_web_response_get_stream (response); if (G_IS_SOCKET_CONNECTION (io_stream)) flags |= COCKPIT_AUTH_COOKIE_INSECURE; headers = cockpit_web_server_new_table (); service = cockpit_auth_login_finish (COCKPIT_AUTH (object), result, flags, headers, &error); if (error) { cockpit_web_response_gerror (response, headers, error); g_error_free (error); } else { creds = cockpit_web_service_get_creds (service); send_login_response (response, creds, headers); g_object_unref (service); } g_hash_table_unref (headers); g_object_unref (response); }
static void handle_login (CockpitHandlerData *data, CockpitWebService *service, const gchar *path, GHashTable *headers, CockpitWebResponse *response) { GHashTable *out_headers; gchar *remote_peer = NULL; GIOStream *io_stream; CockpitCreds *creds; if (service) { out_headers = cockpit_web_server_new_table (); creds = cockpit_web_service_get_creds (service); send_login_response (response, creds, out_headers); g_hash_table_unref (out_headers); } else { io_stream = cockpit_web_response_get_stream (response); remote_peer = get_remote_address (io_stream); cockpit_auth_login_async (data->auth, path, headers, remote_peer, on_login_complete, g_object_ref (response)); g_free (remote_peer); } }
static void cockpit_channel_inject_perform (CockpitChannelInject *inject, CockpitWebResponse *response, CockpitTransport *transport) { static const gchar *marker = "<head>"; CockpitWebFilter *filter; CockpitCreds *creds; const gchar *application; const gchar *checksum; const gchar *host; GString *str; GBytes *base; str = g_string_new (""); if (!inject->service) return; creds = cockpit_web_service_get_creds (inject->service); application = cockpit_creds_get_application (creds); checksum = cockpit_web_service_get_checksum (inject->service, transport); if (checksum) { g_string_printf (str, "\n <base href=\"/%s/$%s%s\">", application, checksum, inject->base_path); } else { host = cockpit_web_service_get_host (inject->service, transport); g_string_printf (str, "\n <base href=\"/%s/@%s%s\">", application, host, inject->base_path); } base = g_string_free_to_bytes (str); filter = cockpit_web_inject_new (marker, base, 1); g_bytes_unref (base); cockpit_web_response_add_filter (response, filter); g_object_unref (filter); }
static gboolean redirect_to_checksum_path (CockpitWebService *service, CockpitWebResponse *response, const gchar *checksum, const gchar *path) { CockpitCreds *creds; gchar *location; const gchar *body; GBytes *bytes; gboolean ret; gsize length; creds = cockpit_web_service_get_creds (service); location = g_strdup_printf ("/%s/$%s%s", cockpit_creds_get_application (creds), checksum, path); body = "<html><head><title>Temporary redirect</title></head>" "<body>Access via checksum</body></html>"; length = strlen (body); cockpit_web_response_headers (response, 307, "Temporary Redirect", length, "Content-Type", "text/html", "Location", location, NULL); g_free (location); bytes = g_bytes_new_static (body, length); ret = cockpit_web_response_queue (response, bytes); if (ret) cockpit_web_response_complete (response); g_bytes_unref (bytes); return ret; }
static GBytes * build_environment (CockpitWebService *service, JsonObject *modules) { const gchar *user; CockpitCreds *creds; JsonObject *env; JsonObject *localhost; JsonObject *languages; JsonObject *language; struct passwd *pwd; gchar *hostname; GBytes *bytes; guint n; const struct { const gchar *name; const gchar *code; } supported_languages[] = { { NC_("display-language", "English"), "" }, { NC_("display-language", "Danish"), "da" }, { NC_("display-language", "German"), "de" }, }; env = json_object_new (); if (service) { creds = cockpit_web_service_get_creds (service); user = cockpit_creds_get_user (creds); json_object_set_string_member (env, "user", user); pwd = cockpit_getpwnam_a (user, NULL); if (pwd) { json_object_set_string_member (env, "name", pwd->pw_gecos); free (pwd); } } localhost = json_object_new (); /* This awkwardly takes the localhost reference */ json_object_set_object_member (env, "localhost", localhost); hostname = g_malloc0 (HOST_NAME_MAX + 1); gethostname (hostname, HOST_NAME_MAX); hostname[HOST_NAME_MAX] = '\0'; json_object_set_string_member (env, "hostname", hostname); /* Only include version info if logged in */ if (service) { json_object_set_string_member (localhost, "version", PACKAGE_VERSION); json_object_set_string_member (localhost, "build_info", COCKPIT_BUILD_INFO); } languages = json_object_new (); /* This awkwardly takes the languages reference */ json_object_set_object_member (localhost, "languages", languages); for (n = 0; n < G_N_ELEMENTS (supported_languages); n++) { language = json_object_new (); json_object_set_object_member (languages, supported_languages[n].code, language); json_object_set_string_member (language, "name", supported_languages[n].name); } if (modules) json_object_set_object_member (localhost, "modules", json_object_ref (modules)); bytes = cockpit_json_write_bytes (env); json_object_unref (env); return bytes; }
gboolean cockpit_handler_external (CockpitWebServer *server, const gchar *original_path, const gchar *path, GIOStream *io_stream, GHashTable *headers, GByteArray *input, CockpitHandlerData *ws) { CockpitWebResponse *response = NULL; CockpitWebService *service = NULL; const gchar *segment = NULL; JsonObject *open = NULL; const gchar *query = NULL; CockpitCreds *creds; const gchar *expected; const gchar *upgrade; guchar *decoded; GBytes *bytes; gsize length; gsize seglen; /* The path must start with /cockpit+xxx/channel/csrftoken? or similar */ if (path && path[0]) segment = strchr (path + 1, '/'); if (!segment) return FALSE; if (!g_str_has_prefix (segment, "/channel/")) return FALSE; segment += 9; /* Make sure we are authenticated, otherwise 404 */ service = cockpit_auth_check_cookie (ws->auth, path, headers); if (!service) return FALSE; creds = cockpit_web_service_get_creds (service); g_return_val_if_fail (creds != NULL, FALSE); expected = cockpit_creds_get_csrf_token (creds); g_return_val_if_fail (expected != NULL, FALSE); /* The end of the token */ query = strchr (segment, '?'); if (query) { seglen = query - segment; query += 1; } else { seglen = strlen (segment); query = ""; } /* No such path is valid */ if (strlen (expected) != seglen || memcmp (expected, segment, seglen) != 0) { g_message ("invalid csrf token"); return FALSE; } decoded = g_base64_decode (query, &length); if (decoded) { bytes = g_bytes_new_take (decoded, length); if (!cockpit_transport_parse_command (bytes, NULL, NULL, &open)) { open = NULL; g_message ("invalid external channel query"); } g_bytes_unref (bytes); } if (!open) { response = cockpit_web_response_new (io_stream, original_path, path, NULL, headers); cockpit_web_response_error (response, 400, NULL, NULL); g_object_unref (response); } else { upgrade = g_hash_table_lookup (headers, "Upgrade"); if (upgrade && g_ascii_strcasecmp (upgrade, "websocket") == 0) { cockpit_channel_socket_open (service, open, original_path, path, io_stream, headers, input); } else { response = cockpit_web_response_new (io_stream, original_path, path, NULL, headers); cockpit_channel_response_open (service, headers, response, open); g_object_unref (response); } json_object_unref (open); } g_object_unref (service); return TRUE; }
static gboolean on_handle_stream_external (CockpitWebServer *server, const gchar *path, GIOStream *io_stream, GHashTable *headers, GByteArray *input, gpointer user_data) { CockpitWebResponse *response; gboolean handled = FALSE; const gchar *upgrade; CockpitCreds *creds; const gchar *expected; const gchar *query; const gchar *segment; JsonObject *open = NULL; GBytes *bytes; guchar *decoded; gsize length; gsize seglen; if (g_str_has_prefix (path, "/cockpit/echosocket")) { const gchar *protocols[] = { "cockpit1", NULL }; const gchar *origins[2] = { NULL, NULL }; WebSocketConnection *ws = NULL; gchar *url; url = g_strdup_printf ("ws://localhost:%u%s", server_port, path); origins[0] = g_strdup_printf ("http://localhost:%u", server_port); ws = web_socket_server_new_for_stream (url, (const gchar **)origins, protocols, io_stream, headers, input); g_signal_connect (ws, "message", G_CALLBACK (on_echo_socket_message), NULL); g_signal_connect (ws, "close", G_CALLBACK (on_echo_socket_close), NULL); return TRUE; } if (!g_str_has_prefix (path, "/cockpit/channel/")) return FALSE; /* Remove /cockpit/channel/ part */ segment = path + 17; if (service) { creds = cockpit_web_service_get_creds (service); g_return_val_if_fail (creds != NULL, FALSE); expected = cockpit_creds_get_csrf_token (creds); g_return_val_if_fail (expected != NULL, FALSE); /* The end of the token */ query = strchr (segment, '?'); if (!query) query = segment + strlen (segment); /* No such path is valid */ seglen = query - segment; if (strlen(expected) == seglen && memcmp (expected, segment, seglen) == 0) { decoded = g_base64_decode (query, &length); if (decoded) { bytes = g_bytes_new_take (decoded, length); if (!cockpit_transport_parse_command (bytes, NULL, NULL, &open)) { open = NULL; g_message ("invalid external channel query"); } g_bytes_unref (bytes); } } if (open) { upgrade = g_hash_table_lookup (headers, "Upgrade"); if (upgrade && g_ascii_strcasecmp (upgrade, "websocket") == 0) { cockpit_channel_socket_open (service, open, path, io_stream, headers, input); handled = TRUE; } else { response = cockpit_web_response_new (io_stream, path, NULL, headers); cockpit_channel_response_open (service, headers, response, open); g_object_unref (response); handled = TRUE; } json_object_unref (open); } } return handled; }