gboolean cockpit_handler_index (CockpitWebServer *server, CockpitWebServerRequestType reqtype, const gchar *path, GHashTable *headers, GBytes *input, CockpitWebResponse *response, CockpitHandlerData *ws) { CockpitWebService *service; if (reqtype != COCKPIT_WEB_SERVER_REQUEST_GET) return FALSE; /* * In the future this code path should also be taken for GSSAPI * single-sign-on authentication, where the user never sees a login * screen. */ service = cockpit_auth_check_cookie (ws->auth, headers); if (service) { /* Already logged in, lookup modules and return full environment */ cockpit_web_service_modules (service, "localhost", on_index_modules, g_object_ref (response)); } else { /* Not logged in, include half-baked environment */ send_index_response (response, NULL, NULL); } return TRUE; }
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; }
/* Called by @server when handling HTTP requests to /socket - runs in a separate * thread dedicated to the request so it may do blocking I/O */ gboolean cockpit_handler_socket (CockpitWebServer *server, CockpitWebServerRequestType reqtype, const gchar *path, GIOStream *io_stream, GHashTable *headers, GByteArray *input, guint in_length, CockpitHandlerData *ws) { CockpitWebService *service; if (!g_str_equal (path, "/socket")) return FALSE; service = cockpit_auth_check_cookie (ws->auth, headers); if (service) { cockpit_web_service_socket (service, io_stream, headers, input); g_object_unref (service); } else { cockpit_web_service_noauth (io_stream, headers, input); } return TRUE; }
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; }
gboolean cockpit_handler_resource (CockpitWebServer *server, const gchar *path, GHashTable *headers, CockpitWebResponse *response, CockpitHandlerData *ws) { CockpitWebService *service; if (g_str_has_prefix (path, "/cockpit/static/")) { cockpit_web_response_file (response, path + 16, TRUE, ws->static_roots); return TRUE; } service = cockpit_auth_check_cookie (ws->auth, headers); if (service) { cockpit_web_service_resource (service, headers, response); g_object_unref (service); } else if (g_str_equal (path, "/") || g_str_has_suffix (path, ".html")) { send_login_html (response, ws); } else { cockpit_web_response_error (response, 401, NULL, NULL); } return TRUE; }
gboolean cockpit_handler_default (CockpitWebServer *server, const gchar *path, GHashTable *headers, CockpitWebResponse *response, CockpitHandlerData *data) { CockpitWebService *service; const gchar *remainder = NULL; gboolean resource; path = cockpit_web_response_get_path (response); g_return_val_if_fail (path != NULL, FALSE); resource = g_str_has_prefix (path, "/cockpit/") || g_str_has_prefix (path, "/cockpit+") || g_str_equal (path, "/cockpit"); // Check for auth service = cockpit_auth_check_cookie (data->auth, path, headers); /* Stuff in /cockpit or /cockpit+xxx */ if (resource) { cockpit_web_response_skip_path (response); remainder = cockpit_web_response_get_path (response); if (!remainder) { cockpit_web_response_error (response, 404, NULL, NULL); return TRUE; } else if (g_str_has_prefix (remainder, "/static/")) { cockpit_branding_serve (service, response, path, remainder + 8, data->os_release, data->branding_roots); return TRUE; } } if (resource) { if (g_str_equal (remainder, "/login")) { handle_login (data, service, path, headers, response); } else { handle_resource (data, service, path, headers, response); } } else { handle_shell (data, service, path, headers, response); } return TRUE; }
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; }
/* Called by @server when handling HTTP requests to /cockpit/socket */ gboolean cockpit_handler_socket (CockpitWebServer *server, const gchar *original_path, const gchar *path, const gchar *method, GIOStream *io_stream, GHashTable *headers, GByteArray *input, CockpitHandlerData *ws) { CockpitWebService *service = NULL; const gchar *segment = NULL; /* * Socket requests should come in on /cockpit/socket or /cockpit+app/socket. * However older javascript may connect on /socket, so we continue to support that. */ if (path && path[0]) segment = strchr (path + 1, '/'); if (!segment) segment = path; if (!segment || !g_str_equal (segment, "/socket")) return FALSE; /* don't support HEAD on a socket, it makes little sense */ if (g_strcmp0 (method, "GET") != 0) return FALSE; if (headers) service = cockpit_auth_check_cookie (ws->auth, path, headers); if (service) { cockpit_web_service_socket (service, path, io_stream, headers, input); g_object_unref (service); } else { handle_noauth_socket (io_stream, path, headers, input); } return TRUE; }
gboolean cockpit_handler_resource (CockpitWebService *server, CockpitWebServerRequestType reqtype, const gchar *path, GHashTable *headers, GBytes *input, CockpitWebResponse *response, CockpitHandlerData *ws) { CockpitWebService *service; service = cockpit_auth_check_cookie (ws->auth, headers); if (service) { cockpit_web_service_resource (service, response); g_object_unref (service); } else { cockpit_web_response_error (response, 401, NULL, NULL); } return TRUE; }
/* Called by @server when handling HTTP requests to /socket - runs in a separate * thread dedicated to the request so it may do blocking I/O */ gboolean cockpit_handler_socket (CockpitWebServer *server, const gchar *path, GIOStream *io_stream, GHashTable *headers, GByteArray *input, guint in_length, CockpitHandlerData *ws) { CockpitWebService *service; const gchar *query = NULL; if (!g_str_has_prefix (path, "/socket")) return FALSE; if (path[7] == '?') query = path + 8; else if (path[7] != '\0') return FALSE; service = cockpit_auth_check_cookie (ws->auth, headers); if (service) { if (query) cockpit_web_service_sideband (service, query, io_stream, headers, input); else cockpit_web_service_socket (service, io_stream, headers, input); g_object_unref (service); } else { cockpit_web_service_noauth (io_stream, headers, input); } return TRUE; }
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; }