diff --git a/src/api/api.c b/src/api/api.c index d99b2b3d..042554a8 100644 --- a/src/api/api.c +++ b/src/api/api.c @@ -118,6 +118,7 @@ int api_handler(struct mg_connection *conn, void *ignored) double_time(), { false, NULL, NULL, NULL, 0u }, { false }, + NULL, { API_FLAG_NONE, 0 } }; diff --git a/src/api/auth.c b/src/api/auth.c index 227b2906..a8fb7e66 100644 --- a/src/api/auth.c +++ b/src/api/auth.c @@ -282,6 +282,7 @@ int check_client_auth(struct ftl_conn *api, const bool is_api) } api->user_id = user_id; + api->session = &auth_data[user_id]; api->message = "correct password"; return user_id; diff --git a/src/api/config.c b/src/api/config.c index 00105327..7ba024f6 100644 --- a/src/api/config.c +++ b/src/api/config.c @@ -1037,6 +1037,16 @@ int api_config(struct ftl_conn *api) if(api->method == HTTP_GET) return api_config_get(api); + // Check if this is an app session and reject the request if app sudo + // mode is disabled + if(api->session != NULL && api->session->app && !config.webserver.api.app_sudo.v.b) + { + return send_json_error(api, 403, + "forbidden", + "config read-only", + "app session but webserver.api.app_sudo is false"); + } + // POST: Create a new config (not supported) // PATCH: Replace parts of the the config with the provided one // PUT: Replaces the entire config with the provided one (not supported diff --git a/src/api/docs/content/specs/config.yaml b/src/api/docs/content/specs/config.yaml index 08d5dd1b..e4324dc5 100644 --- a/src/api/docs/content/specs/config.yaml +++ b/src/api/docs/content/specs/config.yaml @@ -413,6 +413,8 @@ components: type: string app_pwhash: type: string + app_sudo: + type: boolean excludeClients: type: array items: @@ -697,6 +699,7 @@ components: pwhash: '' totp_secret: '' app_pwhash: '' + app_sudo: false excludeClients: [ '1\.2\.3\.4', 'localhost', 'fe80::345' ] excludeDomains: [ 'google\\.de', 'pi-hole\.net' ] maxHistory: 86400 diff --git a/src/config/config.c b/src/config/config.c index 3c025fc7..5c8a1e23 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -1018,6 +1018,12 @@ void initConfig(struct config *conf) conf->webserver.api.app_pwhash.d.s = (char*)""; conf->webserver.api.app_pwhash.c = validate_stub; // Only type-based checking + conf->webserver.api.app_sudo.k = "webserver.api.app_sudo"; + conf->webserver.api.app_sudo.h = "Should the application password be allowed to modify Pi-hole config settings?\n Note that this setting is only relevant if the application password is set. Setting this to true allows third-party applications to modify advanced settings, e.g., the DNS server, DHCP server, or change passwords.\n Be aware that this setting is a security risk and should only be enabled if you trust the application and its developer."; + conf->webserver.api.app_sudo.t = CONF_BOOL; + conf->webserver.api.app_sudo.d.b = false; + conf->webserver.api.app_sudo.c = validate_stub; // Only type-based checking + conf->webserver.api.excludeClients.k = "webserver.api.excludeClients"; conf->webserver.api.excludeClients.h = "Array of clients to be excluded from certain API responses (regex):\n - Query Log (/api/queries)\n - Top Clients (/api/stats/top_clients)\n This setting accepts both IP addresses (IPv4 and IPv6) as well as hostnames.\n Note that backslashes \"\\\" need to be escaped, i.e. \"\\\\\" in this setting\n\n Example: [ \"^192\\\\.168\\\\.2\\\\.56$\", \"^fe80::341:[0-9a-f]*$\", \"^localhost$\" ]"; conf->webserver.api.excludeClients.a = cJSON_CreateStringReference("array of regular expressions describing clients"); diff --git a/src/config/config.h b/src/config/config.h index 1a0587cd..d666c1f5 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -237,6 +237,7 @@ struct config { struct conf_item password; // This is a pseudo-item struct conf_item totp_secret; // This is a write-only item struct conf_item app_pwhash; + struct conf_item app_sudo; struct conf_item excludeClients; struct conf_item excludeDomains; struct conf_item maxHistory; diff --git a/src/webserver/http-common.h b/src/webserver/http-common.h index edc979eb..5ff01564 100644 --- a/src/webserver/http-common.h +++ b/src/webserver/http-common.h @@ -21,6 +21,9 @@ // strlen() #include +// struct session +#include "api/auth.h" + // API-internal definitions // Maximum size of received and processed payload: 64 KB @@ -50,6 +53,7 @@ struct ftl_conn { struct { bool restart; } ftl; + struct session *session; struct api_options opts; }; diff --git a/test/pihole.toml b/test/pihole.toml index e1d72c8b..b2e5f587 100644 --- a/test/pihole.toml +++ b/test/pihole.toml @@ -702,6 +702,14 @@ # app_pwhash = "" + # Should the application password be allowed to modify Pi-hole config settings? + # Note that this setting is only relevant if the application password is set. Setting + # this to true allows third-party applications to modify advanced settings, e.g., the + # DNS server, DHCP server, or change passwords. + # Be aware that this setting is a security risk and should only be enabled if you + # trust the application and its developer. + app_sudo = false + # Array of clients to be excluded from certain API responses (regex): # - Query Log (/api/queries) # - Top Clients (/api/stats/top_clients) @@ -1039,7 +1047,7 @@ all = true ### CHANGED, default = false # Configuration statistics: -# 136 total entries out of which 82 entries are default +# 137 total entries out of which 83 entries are default # --> 54 entries are modified # 2 entries are forced through environment: # - misc.nice