diff --git a/nixos/modules/services/networking/wpa_supplicant.nix b/nixos/modules/services/networking/wpa_supplicant.nix index 61482596763..8a0685c3d96 100644 --- a/nixos/modules/services/networking/wpa_supplicant.nix +++ b/nixos/modules/services/networking/wpa_supplicant.nix @@ -3,6 +3,10 @@ with lib; let + package = if cfg.allowAuxiliaryImperativeNetworks + then pkgs.wpa_supplicant_ro_ssids + else pkgs.wpa_supplicant; + cfg = config.networking.wireless; configFile = if cfg.networks != {} || cfg.extraConfig != "" || cfg.userControlled.enable then pkgs.writeText "wpa_supplicant.conf" '' ${optionalString cfg.userControlled.enable '' @@ -47,6 +51,16 @@ in { description = "Force a specific wpa_supplicant driver."; }; + allowAuxiliaryImperativeNetworks = mkEnableOption "support for imperative & declarative networks" // { + description = '' + Whether to allow configuring networks "imperatively" (e.g. via + wpa_supplicant_gui) and declaratively via + . + + Please note that this adds a custom patch to wpa_supplicant. + ''; + }; + networks = mkOption { type = types.attrsOf (types.submodule { options = { @@ -211,9 +225,9 @@ in { message = ''options networking.wireless."${name}".{psk,pskRaw,auth} are mutually exclusive''; }); - environment.systemPackages = [ pkgs.wpa_supplicant ]; + environment.systemPackages = [ package ]; - services.dbus.packages = [ pkgs.wpa_supplicant ]; + services.dbus.packages = [ package ]; services.udev.packages = [ pkgs.crda ]; # FIXME: start a separate wpa_supplicant instance per interface. @@ -230,13 +244,17 @@ in { wantedBy = [ "multi-user.target" ]; stopIfChanged = false; - path = [ pkgs.wpa_supplicant ]; + path = [ package ]; - script = '' + script = let + configStr = if cfg.allowAuxiliaryImperativeNetworks + then "-c /etc/wpa_supplicant.conf -I ${configFile}" + else "-c ${configFile}"; + in '' if [ -f /etc/wpa_supplicant.conf -a "/etc/wpa_supplicant.conf" != "${configFile}" ] then echo >&2 "<3>/etc/wpa_supplicant.conf present but ignored. Generated ${configFile} is used instead." fi - iface_args="-s -u -D${cfg.driver} -c ${configFile}" + iface_args="-s -u -D${cfg.driver} ${configStr}" ${if ifaces == [] then '' for i in $(cd /sys/class/net && echo *); do DEVTYPE= diff --git a/pkgs/os-specific/linux/wpa_supplicant/0001-Implement-read-only-mode-for-ssids.patch b/pkgs/os-specific/linux/wpa_supplicant/0001-Implement-read-only-mode-for-ssids.patch new file mode 100644 index 00000000000..d459de8a7f3 --- /dev/null +++ b/pkgs/os-specific/linux/wpa_supplicant/0001-Implement-read-only-mode-for-ssids.patch @@ -0,0 +1,130 @@ +From 99ae610f0ae3608a12c864caedf396f14e68327d Mon Sep 17 00:00:00 2001 +From: Maximilian Bosch +Date: Fri, 19 Feb 2021 19:44:21 +0100 +Subject: [PATCH] Implement read-only mode for ssids + +With this change it's possible to define `network=`-sections in a second +config file specified via `-I` without having changes written to +`/etc/wpa_supplicant.conf`. + +This is helpful on e.g. NixOS to allow both declarative (i.e. read-only) +and imperative (i.e. mutable) networks. +--- + wpa_supplicant/config.h | 2 +- + wpa_supplicant/config_file.c | 5 +++-- + wpa_supplicant/config_none.c | 2 +- + wpa_supplicant/config_ssid.h | 2 ++ + wpa_supplicant/wpa_supplicant.c | 8 ++++---- + 5 files changed, 11 insertions(+), 8 deletions(-) + +diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h +index 6a297ecfe..adaf4d398 100644 +--- a/wpa_supplicant/config.h ++++ b/wpa_supplicant/config.h +@@ -1614,7 +1614,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 77c326df5..d5ed051b9 100644 +--- a/wpa_supplicant/config_file.c ++++ b/wpa_supplicant/config_file.c +@@ -373,7 +373,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; +@@ -415,6 +415,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); +@@ -1591,7 +1592,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(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 d5c5c00a9..fd80c079c 100644 +--- a/wpa_supplicant/config_ssid.h ++++ b/wpa_supplicant/config_ssid.h +@@ -93,6 +93,8 @@ struct wpa_ssid { + */ + int id; + ++ int ro; ++ + /** + * priority - Priority group + * +diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c +index 911d79d17..cb0cb99b1 100644 +--- a/wpa_supplicant/wpa_supplicant.c ++++ b/wpa_supplicant/wpa_supplicant.c +@@ -1052,14 +1052,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); +@@ -5638,7 +5638,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); +@@ -5646,7 +5646,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); +-- +2.29.2 + diff --git a/pkgs/os-specific/linux/wpa_supplicant/default.nix b/pkgs/os-specific/linux/wpa_supplicant/default.nix index 80eaf04a114..51af6abde8c 100644 --- a/pkgs/os-specific/linux/wpa_supplicant/default.nix +++ b/pkgs/os-specific/linux/wpa_supplicant/default.nix @@ -1,5 +1,7 @@ { lib, stdenv, fetchurl, fetchpatch, openssl, pkg-config, libnl , dbus, readline ? null, pcsclite ? null + +, readOnlyModeSSIDs ? false }: with lib; @@ -43,6 +45,9 @@ stdenv.mkDerivation rec { url = "https://w1.fi/cgit/hostap/patch/?id=a0541334a6394f8237a4393b7372693cd7e96f15"; sha256 = "1gbhlz41x1ar1hppnb76pqxj6vimiypy7c4kq6h658637s4am3xg"; }) + ] ++ lib.optionals readOnlyModeSSIDs [ + # Allow read-only networks + ./0001-Implement-read-only-mode-for-ssids.patch ]; # TODO: Patch epoll so that the dbus actually responds @@ -134,7 +139,7 @@ stdenv.mkDerivation rec { homepage = "https://w1.fi/wpa_supplicant/"; description = "A tool for connecting to WPA and WPA2-protected wireless networks"; license = licenses.bsd3; - maintainers = with maintainers; [ marcweber ]; + maintainers = with maintainers; [ marcweber ma27 ]; platforms = platforms.linux; }; } diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 7fd7292e06f..3eb535dd41d 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -21080,6 +21080,10 @@ in wpa_supplicant = callPackage ../os-specific/linux/wpa_supplicant { }; + wpa_supplicant_ro_ssids = wpa_supplicant.override { + readOnlyModeSSIDs = true; + }; + wpa_supplicant_gui = libsForQt5.callPackage ../os-specific/linux/wpa_supplicant/gui.nix { }; xf86_input_cmt = callPackage ../os-specific/linux/xf86-input-cmt { };