From patchwork Wed May 5 13:53:43 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maximilian Bosch X-Patchwork-Id: 1474403 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2001:8b0:10b:1:d65d:64ff:fe57:4e05; helo=desiato.infradead.org; envelope-from=hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=desiato.20200630 header.b=Vnx8Gxp8; dkim=fail reason="signature verification failed" (2048-bit key; secure) header.d=infradead.org header.i=@infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=0VHmHf8w; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=mbosch.me header.i=@mbosch.me header.a=rsa-sha256 header.s=mail header.b=e68GYYGJ; dkim-atps=neutral Received: from desiato.infradead.org (desiato.infradead.org [IPv6:2001:8b0:10b:1:d65d:64ff:fe57:4e05]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4Fb1m65M5Gz9sT6 for ; Thu, 6 May 2021 02:06:14 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Type: List-Subscribe:List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id: MIME-Version:Message-ID:Subject:To:From:Date:Reply-To:Cc: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To: References:List-Owner; bh=vKBfUb3MghQXlTTblqybz6RMgzmUJt9MNNuLc5iUWTs=; b=Vnx 8Gxp809NHhc63ukuwhxesfppxxtRr0PZ8JhC4Ew34zEsPmwFTa7G3LeyN6yq7qa2UaIBOnfSvEgN3 THXYLTO2yRLK04UgyngAsaiubwztD2dup8OOVseYZnLhsX2qOWeXhJI1EipJL9mNLAitmDThS7JFF lo0o/dTSr7jysacSBt3uLJSZT0D/x2u1OM4y02mCcDVcrETr7yD3d5RJLQkksKLYIkCZGMqr3DsWD dy+mcYbFL1kBg78RCvLnRSbMLl/pQqt1jBIasvWKQjInBF2gEEB1lUiFy4vnzTS89nDe14oCKIVyZ 37tOqCqvnwnOrYDGMAOupfGPpA/j2bg==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1leK1B-001bkw-3A; Wed, 05 May 2021 16:04:57 +0000 Received: from bombadil.infradead.org ([2607:7c80:54:e::133]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1leHyR-001MBT-D5 for hostap@desiato.infradead.org; Wed, 05 May 2021 13:53:59 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=bombadil.20210309; h=Content-Type:MIME-Version:Message-ID: Subject:To:From:Date:Sender:Reply-To:Cc:Content-Transfer-Encoding:Content-ID: Content-Description:In-Reply-To:References; bh=ekoigOb0IbdaDM3LmU7DJjYdG85yX1JOLmYtEoyKIS8=; b=0VHmHf8wGGk2lpxzGa4q4t7+th RxTLKxBI4ZMBU251tNUBSFcYO4vQqPkdhf0iu89k+rUpLzUydxFemadErI/m0V8IIlQyX8GikXeRx +SnliC3Tov9+ZoG9IsK1kjT61DRqmKVY5zzGDW5bBgWQg+R73tDKufPysX2XrFFicHYXeJlCn4UFu lLjGKaihb0Q90GwZVsX6w5Qd/iw7uK6dJ0WO2JIIgJtOUcn5BPGDjIUWrNwHFFZgzeyYAHY/u+bkC ZIoW868IY9eMVxh6z2NUG7l3v/rqugTPwMQBuNGz1qxAiIB5aHa/lgxdELqJO1KpEL64QQEVXLm2h Ev904SqQ==; Received: from mail.mbosch.me ([188.68.58.50]) by bombadil.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1leHyO-004nIx-1k for hostap@lists.infradead.org; Wed, 05 May 2021 13:53:58 +0000 Date: Wed, 5 May 2021 15:53:43 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=mbosch.me; s=mail; t=1620222824; bh=3dFbsCAkVNKfQTGGRYQGF2+OZTdmZ2n0eopQUB9TKjw=; h=Date:From:To:Subject; b=e68GYYGJzXsvTBUrUZruEyO0XYa/Bv3Bp+VQwfzcdYBNFw1IaJC6snwyHPN8WIK7F nHVfnNknth5+deFdRaMVhboh/G2tLpcv+WIzlzOfsEUvGPqzIDPuRvEOk5ZaXHuWQR wwfFnU9Kt4bylJUKwr47Do7ZUQSYM/Mi5xOYmBbs= From: Maximilian Bosch To: hostap@lists.infradead.org Subject: [PATCH] Implement read-only mode for SSIDs Message-ID: <20210505135343.czilnrvptdhiv2vs@topsnens> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210505_065356_427157_D4188E47 X-CRM114-Status: GOOD ( 27.61 ) X-Spam-Score: -0.2 (/) X-Spam-Report: Spam detection software, running on the system "bombadil.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: On NixOS[1] - a Linux distribution which allows to configure a full OS declaratively - it's possible to configure SSIDs for `wpa_supplicant` like this: networking.wireless.networks = { myssid = { pskRaw = ""; }; }; Content analysis details: (-0.2 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_NONE SPF: sender does not publish an SPF Record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain X-Mailman-Approved-At: Wed, 05 May 2021 17:04:44 +0100 X-BeenThere: hostap@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "Hostap" Errors-To: hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org On NixOS[1] - a Linux distribution which allows to configure a full OS declaratively - it's possible to configure SSIDs for `wpa_supplicant` like this: networking.wireless.networks = { myssid = { pskRaw = ""; }; }; It's also possible to add networks "imperatively" using `wpa_gui` or `wpa_cli`. However it's not possible to do both because if the first option is used, NixOS creates a read-only symlink at `/etc/wpa_supplicant.conf` and then it's not possible for `wpa_supplicant` anymore to write to it. This patch aims to help us changing this: while "declarative" SSID configuration can be quite useful, it's a bad idea for e.g. sensitive stuff like a WPA2 enterprise network. The original idea was to use `-I`[2] for immutable configs (including "declarative" networks) on NixOS and `-c /etc/wpa_supplicant.conf` for anything "imperative". However this doesn't really work out because if a wifi network from a config file specified with `-I` is changed by e.g. `wpa_gui`, it's silently overwritten in `/etc/wpa_supplicant.conf` (specified with `-c`) which is IMHO unintuitive (in our case at least). This patch basically declares each network defined in a config file passed via `-I` to `wpa_supplicant` as "read-only" and doesn't write these "read-only" networks to `/etc/wpa_supplicant.conf`. A bit more context can be found on GitHub in the PR where I implemented this[3]. I know that this is a fairly distro-specific thing and has a rather low chance to actually land in upstream because of that. However I figured that it's still worth a try, especially because `-I` seems to be designed for "global" configuration options only and its behavior if SSIDs are defined in there doesn't seem explicitly defined to me. Last but not least, I'm not a subscriber of this mailing list so while reviewing this, it'd be good if you could leave my email explicitly in the `To:`-section. [1] https://nixos.org/ [2] Added in e6304cad47251e88d073553042f1ea7805a858d1 [3] https://github.com/NixOS/nixpkgs/pull/113716 Signed-off-by: Maximilian Bosch --- wpa_supplicant/config.h | 2 +- wpa_supplicant/config_file.c | 5 +++-- wpa_supplicant/config_none.c | 2 +- wpa_supplicant/config_ssid.h | 15 +++++++++++++++ wpa_supplicant/wpa_supplicant.c | 8 ++++---- 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 68679c6e3..8e0a692c5 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -1731,7 +1731,7 @@ const char * wpa_config_get_global_field_name(unsigned int i, int *no_var); * * Each configuration backend needs to implement this function. */ -struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp); +struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp, int ro); /** * wpa_config_write - Write or update configuration data diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index a535e3f08..0ad5594fc 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -289,7 +289,7 @@ static int wpa_config_process_blob(struct wpa_config *config, FILE *f, #endif /* CONFIG_NO_CONFIG_BLOBS */ -struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp) +struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp, int ro) { FILE *f; char buf[512], *pos; @@ -331,6 +331,7 @@ struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp) while (wpa_config_get_line(buf, sizeof(buf), f, &line, &pos)) { if (os_strcmp(pos, "network={") == 0) { ssid = wpa_config_read_network(f, &line, id++); + ssid->ro = ro; if (ssid == NULL) { wpa_printf(MSG_ERROR, "Line %d: failed to " "parse network block.", line); @@ -1581,7 +1582,7 @@ int wpa_config_write(const char *name, struct wpa_config *config) } for (ssid = config->ssid; ssid; ssid = ssid->next) { - if (ssid->key_mgmt == WPA_KEY_MGMT_WPS || ssid->temporary) + if (ssid->key_mgmt == WPA_KEY_MGMT_WPS || ssid->temporary || ssid->ro) continue; /* do not save temporary networks */ if (wpa_key_mgmt_wpa_psk_no_sae(ssid->key_mgmt) && !ssid->psk_set && !ssid->passphrase) diff --git a/wpa_supplicant/config_none.c b/wpa_supplicant/config_none.c index 2aac28fa3..02191b425 100644 --- a/wpa_supplicant/config_none.c +++ b/wpa_supplicant/config_none.c @@ -17,7 +17,7 @@ #include "base64.h" -struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp) +struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp, int ro) { struct wpa_config *config; diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index 3f7b31480..73f113391 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -104,6 +104,21 @@ struct wpa_ssid { */ int id; + /** + * ro - whether a network is declared as read-only + * + * Every network which is defined in a config file that is passed to + * `wpa_supplicant` using the `-I`-option will be marked as read-only + * using this flag. It has the effect that it won't be written to + * `/etc/wpa_supplicant.conf` if e.g. `wpa_gui` tells the daemon to + * save all changed configs. + * + * This is necessary because networks from `/etc/wpa_supplicant.conf` + * have a higher priority and changes from an alternative file would be + * silently overwritten without this. + */ + int ro; + /** * priority - Priority group * diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 835b33575..278e8b8c2 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1137,14 +1137,14 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s) if (wpa_s->confname == NULL) return -1; - conf = wpa_config_read(wpa_s->confname, NULL); + conf = wpa_config_read(wpa_s->confname, NULL, 0); if (conf == NULL) { wpa_msg(wpa_s, MSG_ERROR, "Failed to parse the configuration " "file '%s' - exiting", wpa_s->confname); return -1; } if (wpa_s->confanother && - !wpa_config_read(wpa_s->confanother, conf)) { + !wpa_config_read(wpa_s->confanother, conf, 1)) { wpa_msg(wpa_s, MSG_ERROR, "Failed to parse the configuration file '%s' - exiting", wpa_s->confanother); @@ -6342,7 +6342,7 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, #else /* CONFIG_BACKEND_FILE */ wpa_s->confname = os_strdup(iface->confname); #endif /* CONFIG_BACKEND_FILE */ - wpa_s->conf = wpa_config_read(wpa_s->confname, NULL); + wpa_s->conf = wpa_config_read(wpa_s->confname, NULL, 0); if (wpa_s->conf == NULL) { wpa_printf(MSG_ERROR, "Failed to read or parse " "configuration '%s'.", wpa_s->confname); @@ -6350,7 +6350,7 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, } wpa_s->confanother = os_rel2abs_path(iface->confanother); if (wpa_s->confanother && - !wpa_config_read(wpa_s->confanother, wpa_s->conf)) { + !wpa_config_read(wpa_s->confanother, wpa_s->conf, 1)) { wpa_printf(MSG_ERROR, "Failed to read or parse configuration '%s'.", wpa_s->confanother);