From 3b345fcd86a0c0aab47c32806f3cc2b65c96447a Mon Sep 17 00:00:00 2001 From: Dustin Falgout Date: Sun, 2 Oct 2016 18:00:15 -0500 Subject: [PATCH] restrict the http requests allowed to be made by the web process. Only local request are allowed. Requests must be for resources within one of the allowed directories (the directories found in lightdm-webkit2-greeter.conf as well as the themes' directory) --- src/webkit2-extension.c | 162 +++++++++++++++++++++++++++++++++++----- 1 file changed, 143 insertions(+), 19 deletions(-) diff --git a/src/webkit2-extension.c b/src/webkit2-extension.c index e26d734..0cca49d 100644 --- a/src/webkit2-extension.c +++ b/src/webkit2-extension.c @@ -31,6 +31,7 @@ * along with lightdm-webkit2-greeter; If not, see . */ +#define _GNU_SOURCE #include #include #include @@ -1487,12 +1488,14 @@ window_object_cleared_callback(WebKitScriptWorld *world, JSGlobalContextRef jsContext; WebKitDOMDOMWindow *dom_window; WebKitDOMDocument *dom_document; + + JSStringRef command; JSObjectRef gettext_object, lightdm_greeter_object, config_file_object, greeter_util_object, globalObject; - JSStringRef command; + gchar *lock_hint_message = "LockHint"; gchar *page_loaded_message = "PageLoaded"; @@ -1685,12 +1688,115 @@ autologin_timer_expired_cb(LightDMGreeter *greeter, WebKitWebExtension *extensio } +static gchar* +get_config_option(const gchar *section, const gchar *key) { + gchar *value; + GError *err = NULL; + + value = g_key_file_get_string(keyfile, section, key, &err); + + if (err) { + g_error(err->message); + g_error_free(err); + return ""; + } + + return value; +} + + +static gboolean +is_requested_file_path_allowed(const char *file_path) { + gchar *background_images_dir; + gchar *user_image; + gchar *logo; + gboolean result = FALSE; + char *normalized_path; + + if (NULL == file_path) { + return result; + } + + GSList* paths = NULL, *iter = NULL; + + paths = g_slist_prepend(paths, THEME_DIR); + + background_images_dir = get_config_option("branding", "background_images"); + paths = g_slist_prepend(paths, background_images_dir); + + user_image = get_config_option("branding", "user_image"); + paths = g_slist_prepend(paths, user_image); + + logo = get_config_option("branding", "logo"); + paths = g_slist_prepend(paths, logo); + + normalized_path = canonicalize_file_name(file_path); + + if (NULL != normalized_path) { + for (iter = paths; iter; iter = iter->next) { + if (strcmp(normalized_path, iter->data) == 0 || g_str_has_prefix(normalized_path, iter->data)) { + /* Requested path is allowed */ + result = TRUE; + break; + } + } + } + + g_slist_free_full(paths, g_free); + g_free(normalized_path); + + return result; +} + + +/** + * Callback for the "send-request" signal of a {@link WebKitWebPage} + * + * @see https://goo.gl/mmoHEx + * @return TRUE to stop other handlers from being invoked for the event (block the request). + * FALSE to continue emission of the event (allow the request). + */ +static gboolean +web_page_send_request_cb(WebKitWebPage *web_page, + WebKitURIRequest *request, + WebKitURIResponse *redirected_response, + gpointer user_data) { + + char *request_scheme; + char *request_file_path; + + const char *request_uri = webkit_uri_request_get_uri(request); + + request_scheme = g_uri_parse_scheme(request_uri); + + if (strcmp(request_scheme, "file") != 0) { + /* In order to ensure the user's privacy & security, only local requests are allowed. */ + g_free(request_scheme); + return TRUE; + } + + request_file_path = g_filename_from_uri(request_uri, NULL, NULL); + + g_free(request_scheme); + + /* Returning TRUE prevents the request, while FALSE allows it :face_with_rolling_eyes: */ + return (FALSE == is_requested_file_path_allowed(request_file_path)); +} + + void page_created_cb(WebKitWebExtension *extension, WebKitWebPage *web_page, gpointer user_data) { page_id = webkit_web_page_get_id(web_page); + + g_signal_connect( + web_page, + "send-request", + G_CALLBACK(web_page_send_request_cb), + NULL + ); } @@ -1700,28 +1806,46 @@ webkit_web_extension_initialize(WebKitWebExtension *extension) { WEB_EXTENSION = extension; - g_signal_connect(G_OBJECT(greeter), - "authentication-complete", - G_CALLBACK(authentication_complete_cb), - extension); + g_signal_connect( + G_OBJECT(greeter), + "authentication-complete", + G_CALLBACK(authentication_complete_cb), + extension + ); - g_signal_connect(G_OBJECT(greeter), - "autologin-timer-expired", - G_CALLBACK(autologin_timer_expired_cb), - extension); + g_signal_connect( + G_OBJECT(greeter), + "autologin-timer-expired", + G_CALLBACK(autologin_timer_expired_cb), + extension + ); + + g_signal_connect( + G_OBJECT(extension), + "page-created", + G_CALLBACK(page_created_cb), + NULL + ); - g_signal_connect(G_OBJECT(extension), - "page-created", - G_CALLBACK(page_created_cb), - NULL); + g_signal_connect( + webkit_script_world_get_default(), + "window-object-cleared", + G_CALLBACK(window_object_cleared_callback), + greeter + ); - g_signal_connect(webkit_script_world_get_default(), - "window-object-cleared", - G_CALLBACK(window_object_cleared_callback), - greeter); + g_signal_connect( + G_OBJECT(greeter), + "show-prompt", + G_CALLBACK(show_prompt_cb), extension + ); - g_signal_connect(G_OBJECT(greeter), "show-prompt", G_CALLBACK(show_prompt_cb), extension); - g_signal_connect(G_OBJECT(greeter), "show-message", G_CALLBACK(show_message_cb), extension); + g_signal_connect( + G_OBJECT(greeter), + "show-message", + G_CALLBACK(show_message_cb), + extension + ); /* TODO: This function was deprecated in lightdm 1.11.x. * New function is lightdm_greeter_connect_to_daemon_sync