gboolean cockpit_handler_logout (CockpitWebServer *server, CockpitWebServerRequestType reqtype, const gchar *path, GHashTable *headers, GBytes *input, CockpitWebResponse *response, CockpitHandlerData *ws) { GIOStream *io_stream; GHashTable *out_headers; const gchar *body; gboolean secure; GBytes *content; io_stream = cockpit_web_response_get_stream (response); secure = !G_IS_SOCKET_CONNECTION (io_stream); out_headers = cockpit_web_server_new_table (); cockpit_auth_logout (ws->auth, headers, secure, out_headers); body ="<html><head><title>Logged out</title></head>" "<body>Logged out</body></html>"; content = g_bytes_new_static (body, strlen (body)); cockpit_web_response_content (response, out_headers, content, NULL); g_bytes_unref (content); g_hash_table_unref (out_headers); return TRUE; }
gboolean cockpit_handler_ping (CockpitWebServer *server, const gchar *path, GHashTable *headers, CockpitWebResponse *response, CockpitHandlerData *ws) { GHashTable *out_headers; const gchar *body; GBytes *content; out_headers = cockpit_web_server_new_table (); /* * The /ping request has unrestricted CORS enabled on it. This allows javascript * in the browser on embedding websites to check if Cockpit is available. These * websites could do this in another way (such as loading an image from Cockpit) * but this does it in the correct manner. * * See: http://www.w3.org/TR/cors/ */ g_hash_table_insert (out_headers, g_strdup ("Access-Control-Allow-Origin"), g_strdup ("*")); g_hash_table_insert (out_headers, g_strdup ("Content-Type"), g_strdup ("application/json")); body ="{ \"service\": \"cockpit\" }"; content = g_bytes_new_static (body, strlen (body)); cockpit_web_response_content (response, out_headers, content, NULL); g_bytes_unref (content); g_hash_table_unref (out_headers); 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; 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 gboolean mock_http_headers (CockpitWebResponse *response, GHashTable *in_headers) { GHashTableIter iter; GHashTable *headers; gpointer name, value; headers = cockpit_web_server_new_table(); g_hash_table_iter_init (&iter, in_headers); while (g_hash_table_iter_next (&iter, &name, &value)) { if (g_str_has_prefix (name, "Header")) g_hash_table_insert (headers, g_strdup (name), g_strdup (value)); } g_hash_table_replace (headers, g_strdup ("Header3"), g_strdup ("three")); g_hash_table_replace (headers, g_strdup ("Header4"), g_strdup ("marmalade")); cockpit_web_response_headers_full (response, 201, "Yoo Hoo", -1, headers); cockpit_web_response_complete (response); g_hash_table_unref (headers); return TRUE; }
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 send_login_html (CockpitWebResponse *response, CockpitHandlerData *ws) { GHashTable *headers = NULL; GList *l, *output = NULL; gchar *login_html; GMappedFile *file; GError *error = NULL; GBytes *body = NULL; gsize length; login_html = g_build_filename (ws->static_roots[0], "login.html", NULL); file = g_mapped_file_new (login_html, FALSE, &error); if (file == NULL) { g_warning ("%s: %s", login_html, error->message); cockpit_web_response_error (response, 500, NULL, NULL); g_clear_error (&error); goto out; } body = g_mapped_file_get_bytes (file); output = cockpit_template_expand (body, substitute_environment, ws->os_release); length = 0; for (l = output; l != NULL; l = g_list_next (l)) length += g_bytes_get_size (l->data); headers = cockpit_web_server_new_table (); g_hash_table_insert (headers, g_strdup ("Content-Type"), g_strdup ("text/html; charset=utf8")); cockpit_web_response_headers_full (response, 200, "OK", length, headers); for (l = output; l != NULL; l = g_list_next (l)) { if (!cockpit_web_response_queue (response, l->data)) break; } if (l == NULL) cockpit_web_response_complete (response); out: g_list_free_full (output, (GDestroyNotify)g_bytes_unref); if (headers) g_hash_table_unref (headers); g_free (login_html); if (body) g_bytes_unref (body); if (file) g_mapped_file_unref (file); }
void cockpit_channel_response_open (CockpitWebService *service, GHashTable *in_headers, CockpitWebResponse *response, JsonObject *open) { CockpitTransport *transport; WebSocketDataType data_type; GHashTable *headers; const gchar *content_type; const gchar *content_disposition; /* Parse the external */ if (!cockpit_web_service_parse_external (open, &content_type, &content_disposition, NULL)) { cockpit_web_response_error (response, 400, NULL, "Bad channel request"); return; } transport = cockpit_web_service_ensure_transport (service, open); if (!transport) { cockpit_web_response_error (response, 502, NULL, "Failed to open channel transport"); return; } headers = cockpit_web_server_new_table (); if (content_disposition) g_hash_table_insert (headers, g_strdup ("Content-Disposition"), g_strdup (content_disposition)); if (!json_object_has_member (open, "binary")) json_object_set_string_member (open, "binary", "raw"); if (!content_type) { if (!cockpit_web_service_parse_binary (open, &data_type)) g_return_if_reached (); if (data_type == WEB_SOCKET_DATA_TEXT) content_type = "text/plain"; else content_type = "application/octet-stream"; } g_hash_table_insert (headers, g_strdup ("Content-Type"), g_strdup (content_type)); /* We shouldn't need to send this part further */ json_object_remove_member (open, "external"); cockpit_channel_response_create (service, response, transport, NULL, headers, open); g_hash_table_unref (headers); }
static gboolean mock_http_host (CockpitWebResponse *response, GHashTable *in_headers) { GHashTable *headers; headers = cockpit_web_server_new_table(); g_hash_table_insert (headers, g_strdup ("Host"), g_strdup (g_hash_table_lookup (in_headers, "Host"))); cockpit_web_response_headers_full (response, 201, "Yoo Hoo", -1, headers); cockpit_web_response_complete (response); g_hash_table_unref (headers); return TRUE; }
static void on_login_complete (GObject *object, GAsyncResult *result, gpointer user_data) { CockpitWebResponse *response = user_data; GError *error = NULL; JsonObject *response_data = NULL; GHashTable *headers; GIOStream *io_stream; GBytes *content; io_stream = cockpit_web_response_get_stream (response); headers = cockpit_web_server_new_table (); response_data = cockpit_auth_login_finish (COCKPIT_AUTH (object), result, io_stream, headers, &error); /* Never cache a login response */ cockpit_web_response_set_cache_type (response, COCKPIT_WEB_RESPONSE_NO_CACHE); if (error) { if (response_data) { g_hash_table_insert (headers, g_strdup ("Content-Type"), g_strdup ("application/json")); content = cockpit_json_write_bytes (response_data); cockpit_web_response_headers_full (response, 401, "Authentication required", -1, headers); cockpit_web_response_queue (response, content); cockpit_web_response_complete (response); g_bytes_unref (content); } else { cockpit_web_response_gerror (response, headers, error); } g_error_free (error); } else { send_login_response (response, response_data, headers); } if (response_data) json_object_unref (response_data); g_hash_table_unref (headers); g_object_unref (response); }
gboolean cockpit_handler_login (CockpitWebServer *server, CockpitWebServerRequestType reqtype, const gchar *path, GHashTable *headers, GBytes *input, CockpitWebResponse *response, CockpitHandlerData *ws) { CockpitWebService *service; gchar *remote_peer = NULL; GIOStream *io_stream; LoginResponse *lr; lr = g_new0 (LoginResponse, 1); lr->response = g_object_ref (response); lr->headers = cockpit_web_server_new_table (); if (reqtype == COCKPIT_WEB_SERVER_REQUEST_GET) { service = cockpit_auth_check_cookie (ws->auth, headers); if (service == NULL) { cockpit_web_response_error (response, 401, NULL, NULL); login_response_free (lr); } else { cockpit_web_service_modules (service, "localhost", on_login_modules, lr); g_object_unref (service); /* no response yet */ } } else if (reqtype == COCKPIT_WEB_SERVER_REQUEST_POST) { io_stream = cockpit_web_response_get_stream (response); remote_peer = get_remote_address (io_stream); cockpit_auth_login_async (ws->auth, headers, input, remote_peer, on_login_complete, lr); g_free (remote_peer); /* no response yet */ } return TRUE; }
gboolean cockpit_web_server_parse_cookies (GHashTable *headers, GHashTable **out_cookies, GError **error) { gboolean ret = FALSE; GHashTableIter hash_iter; const gchar *key; const gchar *value; gs_unref_hashtable GHashTable *ret_cookies = NULL; ret_cookies = cockpit_web_server_new_table (); g_hash_table_iter_init (&hash_iter, headers); while (g_hash_table_iter_next (&hash_iter, (gpointer)&key, (gpointer)&value)) { if (g_ascii_strcasecmp (key, "Cookie") == 0) { gs_strfreev gchar** elements = NULL; guint n; elements = g_strsplit (value, ";", 0); for (n = 0; elements[n] != NULL; n++) { gchar *cookie_name; gchar *cookie_value; g_strstrip(elements[n]); if (!parse_cookie_pair (elements[n], &cookie_name, &cookie_value, error)) goto out; /* adopt strings */ g_hash_table_replace (ret_cookies, cookie_name, cookie_value); } } } ret = TRUE; *out_cookies = ret_cookies; ret_cookies = NULL; out: return ret; }
void cockpit_channel_response_serve (CockpitWebService *service, GHashTable *in_headers, CockpitWebResponse *response, const gchar *where, const gchar *path) { CockpitChannelResponse *chesp = NULL; CockpitTransport *transport = NULL; CockpitCacheType cache_type = COCKPIT_WEB_RESPONSE_CACHE_PRIVATE; const gchar *host = NULL; const gchar *pragma; gchar *quoted_etag = NULL; GHashTable *out_headers = NULL; gchar *val = NULL; gboolean handled = FALSE; GHashTableIter iter; const gchar *checksum; JsonObject *object = NULL; JsonObject *heads; gchar *channel = NULL; gchar *language = NULL; gpointer key; gpointer value; g_return_if_fail (COCKPIT_IS_WEB_SERVICE (service)); g_return_if_fail (in_headers != NULL); g_return_if_fail (COCKPIT_IS_WEB_RESPONSE (response)); g_return_if_fail (path != NULL); if (where == NULL) { host = "localhost"; } else if (where[0] == '@') { host = where + 1; } else if (where[0] == '$') { quoted_etag = g_strdup_printf ("\"%s\"", where); cache_type = COCKPIT_WEB_RESPONSE_CACHE_FOREVER; pragma = g_hash_table_lookup (in_headers, "Pragma"); if ((!pragma || !strstr (pragma, "no-cache")) && (g_strcmp0 (g_hash_table_lookup (in_headers, "If-None-Match"), where) == 0 || g_strcmp0 (g_hash_table_lookup (in_headers, "If-None-Match"), quoted_etag) == 0)) { cockpit_web_response_headers (response, 304, "Not Modified", 0, "ETag", quoted_etag, NULL); cockpit_web_response_complete (response); handled = TRUE; goto out; } transport = cockpit_web_service_find_transport (service, where + 1); if (!transport) goto out; host = cockpit_web_service_get_host (service, transport); if (!host) { g_warn_if_reached (); goto out; } } else { goto out; } cockpit_web_response_set_cache_type (response, cache_type); object = cockpit_transport_build_json ("command", "open", "payload", "http-stream1", "internal", "packages", "method", "GET", "host", host, "path", path, "binary", "raw", NULL); if (!transport) { transport = cockpit_web_service_ensure_transport (service, object); if (!transport) goto out; } if (where) { /* * Maybe send back a redirect to the checksum url. We only do this if actually * accessing a file, and not a some sort of data like '/checksum', or a root path * like '/' */ if (where[0] == '@' && strchr (path, '.')) { checksum = cockpit_web_service_get_checksum (service, transport); if (checksum) { handled = redirect_to_checksum_path (service, response, checksum, path); goto out; } } } out_headers = cockpit_web_server_new_table (); channel = cockpit_web_service_unique_channel (service); json_object_set_string_member (object, "channel", channel); if (quoted_etag) { /* * If we have a checksum, then use it as an ETag. It is intentional that * a cockpit-bridge version could (in the future) override this. */ g_hash_table_insert (out_headers, g_strdup ("ETag"), quoted_etag); quoted_etag = NULL; } heads = json_object_new (); g_hash_table_iter_init (&iter, in_headers); while (g_hash_table_iter_next (&iter, &key, &value)) { val = NULL; if (g_ascii_strcasecmp (key, "Host") == 0 || g_ascii_strcasecmp (key, "Cookie") == 0 || g_ascii_strcasecmp (key, "Referer") == 0 || g_ascii_strcasecmp (key, "Connection") == 0 || g_ascii_strcasecmp (key, "Pragma") == 0 || g_ascii_strcasecmp (key, "Cache-Control") == 0 || g_ascii_strcasecmp (key, "User-Agent") == 0 || g_ascii_strcasecmp (key, "Accept-Charset") == 0 || g_ascii_strcasecmp (key, "Accept-Ranges") == 0 || g_ascii_strcasecmp (key, "Content-Length") == 0 || g_ascii_strcasecmp (key, "Content-MD5") == 0 || g_ascii_strcasecmp (key, "Content-Range") == 0 || g_ascii_strcasecmp (key, "Range") == 0 || g_ascii_strcasecmp (key, "TE") == 0 || g_ascii_strcasecmp (key, "Trailer") == 0 || g_ascii_strcasecmp (key, "Upgrade") == 0 || g_ascii_strcasecmp (key, "Transfer-Encoding") == 0) continue; json_object_set_string_member (heads, key, value); g_free (val); } /* Parse the language out of the CockpitLang cookie */ language = cockpit_web_server_parse_cookie (in_headers, "CockpitLang"); if (language) json_object_set_string_member (heads, "Accept-Language", language); json_object_set_string_member (heads, "Host", host); json_object_set_object_member (object, "headers", heads); chesp = cockpit_channel_response_create (service, response, transport, cockpit_web_response_get_path (response), out_headers, object); if (!where) chesp->inject = cockpit_channel_inject_new (service, path); handled = TRUE; out: g_free (language); if (object) json_object_unref (object); g_free (quoted_etag); if (out_headers) g_hash_table_unref (out_headers); g_free (channel); if (!handled) cockpit_web_response_error (response, 404, NULL, NULL); }
static void send_index_response (CockpitWebResponse *response, CockpitWebService *service, JsonObject *modules) { GHashTable *out_headers; GError *error = NULL; GMappedFile *file = NULL; GBytes *body = NULL; GBytes *prefix = NULL; GBytes *environ = NULL; GBytes *suffix = NULL; gchar *index_html; const gchar *needle; const gchar *data; const gchar *pos; gsize needle_len; gsize length; gsize offset; /* * Since the index file cannot be properly cached, it can change on * each request, so we include full environment information directly * rather than making the client do another round trip later. * * If the caller is already logged in, then this is included in the * environment. */ index_html = g_build_filename (cockpit_ws_static_directory, "index.html", NULL); file = g_mapped_file_new (index_html, FALSE, &error); if (file == NULL) { g_warning ("%s: %s", index_html, error->message); cockpit_web_response_error (response, 500, NULL, NULL); g_clear_error (&error); goto out; } body = g_mapped_file_get_bytes (file); data = g_bytes_get_data (body, &length); needle = "cockpit_environment_info"; pos = g_strstr_len (data, length, needle); if (!pos) { g_warning ("couldn't find 'cockpit_environment_info' string in index.html"); cockpit_web_response_error (response, 500, NULL, NULL); goto out; } environ = build_environment (service, modules); offset = (pos - data); prefix = g_bytes_new_from_bytes (body, 0, offset); needle_len = strlen (needle); suffix = g_bytes_new_from_bytes (body, offset + needle_len, length - (offset + needle_len)); out_headers = cockpit_web_server_new_table (); g_hash_table_insert (out_headers, g_strdup ("Content-Type"), g_strdup ("text/html; charset=utf8")); cockpit_web_response_content (response, out_headers, prefix, environ, suffix, NULL); g_hash_table_unref (out_headers); out: g_free (index_html); if (prefix) g_bytes_unref (prefix); if (body) g_bytes_unref (body); if (environ) g_bytes_unref (environ); if (suffix) g_bytes_unref (suffix); if (file) g_mapped_file_unref (file); }