diff --git a/nixos/doc/manual/release-notes/rl-2605.section.md b/nixos/doc/manual/release-notes/rl-2605.section.md
index fc7801aa0c1c5..3317a4d8a43b5 100644
--- a/nixos/doc/manual/release-notes/rl-2605.section.md
+++ b/nixos/doc/manual/release-notes/rl-2605.section.md
@@ -55,6 +55,16 @@ of pulling the upstream container image from Docker Hub. If you want the old beh
- The Bash implementation of the `nixos-rebuild` program is removed. All switchable systems now use the Python rewrite. Any prior usage of `system.rebuild.enableNg` must now be removed. If you have any outstanding issues with the new implementation, please open an issue on GitHub.
+- The `networking.wireless` module has been security hardened: the `wpa_supplicant` daemon now runs under an unprivileged user with restricted access to the system.
+
+ As part of these changes, `/etc/wpa_supplicant.conf` has been deprecated: the NixOS-generated configuration file is now linked to `/etc/wpa_supplicant/nixos.conf` and `/etc/wpa_supplicant/imperative.conf` has been added for imperatively configuring `wpa_supplicant` or when using [allowAuxiliaryImperativeNetworks](#opt-networking.wireless.allowAuxiliaryImperativeNetworks).
+
+ If client certificates, keys or other files are needed, these should be stored under `/etc/wpa_supplicant` and owned by `wpa_supplicant` to ensure the daemon can read them.
+
+ Also, the {option}`networking.wireless.userControlled.group` option has been removed since there is now a dedicated `wpa_supplicant` group to control the daemon, and {option}`networking.wireless.userControlled.enable` has been renamed to [](#opt-networking.wireless.userControlled).
+
+ No functionality should have been impacted by these changes (including controlling via `wpa_cli`, integration with NetworkManager or connman), but if you find any problems, please open an issue on GitHub.
+
- `services.angrr` now uses TOML for configuration. Define policies with `services.angrr.settings` (generate TOML file) or point to a file using `services.angrr.configFile`. The legacy options `services.angrr.period`, `services.angrr.ownedOnly`, and `services.angrr.removeRoot` have been removed. See `man 5 angrr` and the description of `services.angrr.settings` options for examples and details.
- `services.pingvin-share` has been removed as the `pingvin-share.backend` package was broken and the project was archived upstream.
diff --git a/nixos/modules/services/networking/connman.nix b/nixos/modules/services/networking/connman.nix
index d3a8e236358e3..45168c643ee90 100644
--- a/nixos/modules/services/networking/connman.nix
+++ b/nixos/modules/services/networking/connman.nix
@@ -165,6 +165,7 @@ in
wireless = {
enable = lib.mkIf (!enableIwd) true;
dbusControlled = true;
+ autoDetectInterfaces = false;
iwd = lib.mkIf enableIwd {
enable = true;
};
diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix
index 9295157b793b8..f76e649d75e90 100644
--- a/nixos/modules/services/networking/networkmanager.nix
+++ b/nixos/modules/services/networking/networkmanager.nix
@@ -11,7 +11,8 @@ let
cfg = config.networking.networkmanager;
ini = pkgs.formats.ini { };
- delegateWireless = config.networking.wireless.enable == true && cfg.unmanaged != [ ];
+ # Whether wpa_supplicant is managed independently
+ delegateWireless = config.networking.wireless.networks != { } && cfg.unmanaged != [ ];
enableIwd = cfg.wifi.backend == "iwd";
@@ -136,10 +137,7 @@ let
cfg.package
]
++ cfg.plugins
- ++ pluginRuntimeDeps
- ++ lib.optionals (!delegateWireless && !enableIwd) [
- pkgs.wpa_supplicant
- ];
+ ++ pluginRuntimeDeps;
in
{
@@ -541,9 +539,9 @@ in
assertions = [
{
- assertion = config.networking.wireless.enable == true -> cfg.unmanaged != [ ];
+ assertion = config.networking.wireless.networks != { } -> cfg.unmanaged != [ ];
message = ''
- You can not use networking.networkmanager with networking.wireless.
+ You can not use networking.networkmanager with networking.wireless.networks.
Except if you mark some interfaces as unmanaged by NetworkManager.
'';
}
@@ -676,6 +674,13 @@ in
useDHCP = false;
})
+ (mkIf (!delegateWireless && !enableIwd) {
+ # Enable wpa_supplicant but fully control it over DBus
+ wireless.enable = true;
+ wireless.autoDetectInterfaces = false;
+ wireless.dbusControlled = true;
+ })
+
(mkIf enableIwd {
wireless.iwd.enable = true;
})
diff --git a/nixos/modules/services/networking/wpa_supplicant.nix b/nixos/modules/services/networking/wpa_supplicant.nix
index 5bcc5e5c38d85..124bd9c9eda0d 100644
--- a/nixos/modules/services/networking/wpa_supplicant.nix
+++ b/nixos/modules/services/networking/wpa_supplicant.nix
@@ -48,31 +48,6 @@ let
else
networkList;
- # Content of wpa_supplicant.conf
- generatedConfig = concatStringsSep "\n" (
- (map mkNetwork allNetworks)
- ++ optional cfg.userControlled.enable (
- concatStringsSep "\n" [
- "ctrl_interface=/run/wpa_supplicant"
- "ctrl_interface_group=${cfg.userControlled.group}"
- "update_config=1"
- ]
- )
- ++ [ "pmf=1" ]
- ++ optional (cfg.secretsFile != null) "ext_password_backend=file:${cfg.secretsFile}"
- ++ optional cfg.scanOnLowSignal ''bgscan="simple:30:-70:3600"''
- ++ optional (cfg.extraConfig != "") cfg.extraConfig
- );
-
- configIsGenerated = with cfg; networks != { } || extraConfig != "" || userControlled.enable;
-
- # the original configuration file
- configFile =
- if configIsGenerated then
- pkgs.writeText "wpa_supplicant.conf" generatedConfig
- else
- "/etc/wpa_supplicant.conf";
-
# Creates a network block for wpa_supplicant.conf
mkNetwork =
opts:
@@ -104,6 +79,12 @@ let
}
'';
+ hasDeclarative = lib.any id [
+ (cfg.networks != { })
+ (cfg.extraConfig != "")
+ cfg.userControlled
+ ];
+
# Creates a systemd unit for wpa_supplicant bound to a given (or any) interface
mkUnit =
iface:
@@ -114,9 +95,11 @@ let
configStr =
(
if cfg.allowAuxiliaryImperativeNetworks then
- "-c /etc/wpa_supplicant.conf -I ${configFile}"
+ "-c /etc/wpa_supplicant/imperative.conf -I /etc/wpa_supplicant/nixos.conf"
+ else if hasDeclarative then
+ "-c /etc/wpa_supplicant/nixos.conf"
else
- "-c ${configFile}"
+ "-c /etc/wpa_supplicant/imperative.conf"
)
+ lib.concatMapStrings (p: " -I " + p) cfg.extraConfigFiles;
in
@@ -128,32 +111,100 @@ let
wants = [ "network.target" ];
requires = deviceUnit;
wantedBy = [ "multi-user.target" ];
+
stopIfChanged = false;
+ restartTriggers = [ config.environment.etc."wpa_supplicant/nixos.conf".source ];
path = [ pkgs.wpa_supplicant ];
- # if `userControl.enable`, the supplicant automatically changes the permissions
- # and owning group of the runtime dir; setting `umask` ensures the generated
- # config file isn't readable (except to root); see nixpkgs#267693
- serviceConfig.UMask = "066";
- serviceConfig.RuntimeDirectory = "wpa_supplicant";
- serviceConfig.RuntimeDirectoryMode = "700";
+ serviceConfig = {
+ User = "wpa_supplicant";
+ Group = "wpa_supplicant";
+ RuntimeDirectory = "wpa_supplicant";
+ AmbientCapabilities = [
+ "CAP_NET_ADMIN"
+ "CAP_NET_RAW"
+ ];
+ CapabilityBoundingSet = [
+ "CAP_NET_ADMIN"
+ "CAP_NET_RAW"
+ ];
+ RootDirectory = "/run/wpa_supplicant";
+ RootDirectoryStartOnly = true;
+ BindPaths = [
+ "/etc/wpa_supplicant" # to write wpa_supplicant.conf{,.tmp}
+ "/run/wpa_supplicant" # to make control sockets
+ # to set up interfaces
+ "/proc/sys/net"
+ "/dev/rfkill"
+ ]
+ ++ lib.optional cfg.dbusControlled "/run/dbus"
+ ++ lib.optional cfg.allowAuxiliaryImperativeNetworks "/etc/wpa_supplicant";
+ BindReadOnlyPaths = [
+ builtins.storeDir
+ "/etc/"
+ ]
+ ++ lib.optional (cfg.secretsFile != null) cfg.secretsFile;
+ DeviceAllow = "/dev/rfkill rw";
+ LockPersonality = true;
+ MemoryDenyWriteExecute = true;
+ NoNewPrivileges = true;
+ PrivateDevices = true;
+ PrivateMounts = true;
+ PrivateTmp = true;
+ PrivateUsers = false;
+ ProtectClock = true;
+ ProtectControlGroups = true;
+ ProtectHome = true;
+ ProtectHostname = true;
+ ProtectKernelLogs = true;
+ ProtectKernelModules = true;
+ ProtectKernelTunables = true;
+ ProtectProc = "invisible";
+ ProtectSystem = "strict";
+ IPAddressDeny = "any";
+ RemoveIPC = true;
+ RestrictAddressFamilies = [
+ "AF_UNIX"
+ "AF_INET"
+ "AF_INET6"
+ "AF_NETLINK"
+ "AF_PACKET"
+ ];
+ RestrictNamespaces = true;
+ RestrictRealtime = true;
+ RestrictSUIDSGID = true;
+ SystemCallFilter = [
+ "@system-service"
+ "~@keyring"
+ "~@resources"
+ ];
+ SystemCallArchitectures = "native";
+ UMask = "0077";
+
+ ExecStartPre =
+ lib.optionals (cfg.allowAuxiliaryImperativeNetworks || !hasDeclarative) [
+ # set up imperative config file
+ "+${pkgs.coreutils}/bin/touch /etc/wpa_supplicant/imperative.conf"
+ "+${pkgs.coreutils}/bin/chmod 664 /etc/wpa_supplicant/imperative.conf"
+ "+${pkgs.coreutils}/bin/chown -R wpa_supplicant:wpa_supplicant /etc/wpa_supplicant"
+ ]
+ ++ lib.optionals cfg.userControlled [
+ # set up client sockets directory
+ "+${pkgs.coreutils}/bin/mkdir /run/wpa_supplicant/client"
+ "+${pkgs.coreutils}/bin/chown wpa_supplicant:wpa_supplicant /run/wpa_supplicant/client"
+ "+${pkgs.coreutils}/bin/chmod g=u /run/wpa_supplicant/client"
+ ];
+ };
script = ''
- ${optionalString (configIsGenerated && !cfg.allowAuxiliaryImperativeNetworks) ''
- if [ -f /etc/wpa_supplicant.conf ]; then
- echo >&2 "<3>/etc/wpa_supplicant.conf present but ignored. Generated ${configFile} is used instead."
- fi
- ''}
-
- # ensure wpa_supplicant.conf exists, or the daemon will fail to start
- ${optionalString cfg.allowAuxiliaryImperativeNetworks ''
- touch /etc/wpa_supplicant.conf
- ''}
-
iface_args="-s ${optionalString cfg.dbusControlled "-u"} -D${cfg.driver} ${configStr}"
-
${
- if iface == null then
+ if iface != null then
+ ''
+ # add known interface to the daemon arguments
+ args="-i${iface} $iface_args"
+ ''
+ else if cfg.autoDetectInterfaces then
''
# detect interfaces automatically
@@ -176,10 +227,7 @@ let
done
''
else
- ''
- # add known interface to the daemon arguments
- args="-i${iface} $iface_args"
- ''
+ "args=$iface_args"
}
# finally start daemon
@@ -205,7 +253,8 @@ in
"wlan1"
];
description = ''
- The interfaces {command}`wpa_supplicant` will use. If empty, it will
+ The interfaces {command}`wpa_supplicant` will use. If empty and
+ [](#opt-networking.wireless.autoDetectInterfaces) is true it will
automatically use all wireless interfaces.
::: {.note}
@@ -214,6 +263,10 @@ in
'';
};
+ autoDetectInterfaces = mkEnableOption "automatic detection of wireless interfaces" // {
+ default = true;
+ };
+
driver = mkOption {
type = types.str;
default = "nl80211,wext";
@@ -503,27 +556,36 @@ in
'';
};
- userControlled = {
- enable = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Allow normal users to control wpa_supplicant through wpa_gui or wpa_cli.
- This is useful for laptop users that switch networks a lot and don't want
- to depend on a large package such as NetworkManager just to pick nearby
- access points.
-
- When using a declarative network specification you cannot persist any
- settings via wpa_gui or wpa_cli.
- '';
- };
+ userControlled = mkOption {
+ type =
+ with types;
+ coercedTo attrs (
+ val:
+ if builtins.isAttrs val && val ? enable then
+ trace "Obsolete option `networking.wireless.userControlled.enable' is used. It was renamed to networking.wireless.userControlled" val.enable
+ else if builtins.isAttrs val && val ? group then
+ trace
+ "The option definition `networking.wireless.userControlled.group' no longer has any effect. The group is now fixed to `wpa_supplicant'."
+ (val.enable or false)
+ else if builtins.isBool val then
+ val
+ else
+ false
+ ) bool;
+ default = false;
+ description = ''
+ Allow users of the `wpa_supplicant` group to control wpa_supplicant
+ through wpa_gui or wpa_cli.
+ This is useful for laptop users that switch networks a lot and don't want
+ to depend on a large package such as NetworkManager just to pick nearby
+ access points.
- group = mkOption {
- type = types.str;
- default = "wheel";
- example = "network";
- description = "Members of this group can control wpa_supplicant.";
- };
+ ::: {.note}
+ When networks are configured declaratively, you cannot persist any settings
+ via wpa_gui or wpa_cli, unless {option}`allowAuxiliaryImperativeNetworks`
+ is used.
+ :::
+ '';
};
dbusControlled = mkOption {
@@ -624,9 +686,33 @@ in
}
];
+ users.groups.wpa_supplicant = { };
+ users.users.wpa_supplicant = {
+ isSystemUser = true;
+ group = "wpa_supplicant";
+ description = "WPA Supplicant user";
+ };
+
hardware.wirelessRegulatoryDatabase = true;
environment.systemPackages = [ pkgs.wpa_supplicant ];
+
+ # NixOS-generated configuration files
+ environment.etc."wpa_supplicant/nixos.conf".text = concatStringsSep "\n" (
+ (map mkNetwork allNetworks)
+ ++ optional cfg.userControlled (
+ concatStringsSep "\n" [
+ "ctrl_interface=/run/wpa_supplicant/control"
+ "ctrl_interface_group=wpa_supplicant"
+ "update_config=1"
+ ]
+ )
+ ++ [ "pmf=1" ]
+ ++ optional (cfg.secretsFile != null) "ext_password_backend=file:${cfg.secretsFile}"
+ ++ optional cfg.scanOnLowSignal ''bgscan="simple:30:-70:3600"''
+ ++ optional (cfg.extraConfig != "") cfg.extraConfig
+ );
+
services.dbus.packages = optional cfg.dbusControlled pkgs.wpa_supplicant;
systemd.services =
diff --git a/nixos/tests/wpa_supplicant.nix b/nixos/tests/wpa_supplicant.nix
index d7aaaf8a14299..921c111cfc1fd 100644
--- a/nixos/tests/wpa_supplicant.nix
+++ b/nixos/tests/wpa_supplicant.nix
@@ -94,20 +94,30 @@ let
};
};
+ # Note: secrets are stored outside /etc/ and /nix/store to
+ # test for accessibility of these paths
+ system.activationScripts.wpa-secrets = {
+ deps = [
+ "users"
+ "specialfs"
+ ];
+ text = ''
+ install -Dm600 -o wpa_supplicant ${pkgs.writeText "wpa" ''
+ psk_nixos_test=${naughtyPassphrase}
+ ''} /var/lib/secrets/wpa
+ '';
+ };
+
# wireless client
networking.wireless = lib.mkMerge [
{
# the override is needed because the wifi is
# disabled with mkVMOverride in qemu-vm.nix.
enable = lib.mkOverride 0 true;
- userControlled.enable = true;
+ userControlled = true;
interfaces = [ "wlan1" ];
fallbackToWPA2 = lib.mkDefault true;
-
- # secrets
- secretsFile = pkgs.writeText "wpa-secrets" ''
- psk_nixos_test=${naughtyPassphrase}
- '';
+ secretsFile = "/var/lib/secrets/wpa";
}
extraConfig
];
@@ -142,7 +152,8 @@ in
# the override is needed because the wifi is
# disabled with mkVMOverride in qemu-vm.nix.
enable = lib.mkOverride 0 true;
- userControlled.enable = true;
+ userControlled = true;
+ dbusControlled = true;
fallbackToWPA2 = true;
networks = {
@@ -198,9 +209,14 @@ in
assert "Failed to connect" not in status, \
"Failed to connect to the daemon"
- # get the configuration file
- cmdline = machine.succeed("cat /proc/$(pgrep wpa)/cmdline").split('\x00')
- config_file = cmdline[cmdline.index("-c") + 1]
+ with subtest("D-Bus interface is working"):
+ dbus_command = "dbus-send --system --print-reply --dest=fi.w1.wpa_supplicant1 " \
+ "/fi/w1/wpa_supplicant1 fi.w1.wpa_supplicant1.GetInterface string:wlan0"
+ machine.succeed(dbus_command) # as root
+ machine.succeed(f"sudo -g wpa_supplicant {dbus_command}") # as wpa_supplicant group
+
+ # generated configuration file
+ config_file = "/etc/static/wpa_supplicant/nixos.conf"
with subtest("WPA2 fallbacks have been generated"):
assert int(machine.succeed(f"grep -c sae-only {config_file}")) == 1
@@ -218,6 +234,9 @@ in
# save file for manual inspection
machine.copy_from_vm(config_file)
+
+ # check hardening options
+ machine.succeed("systemd-analyze security wpa_supplicant >&2")
'';
};
@@ -233,25 +252,27 @@ in
# wireless client
networking.wireless = {
enable = lib.mkOverride 0 true;
- userControlled.enable = true;
+ userControlled = true;
allowAuxiliaryImperativeNetworks = true;
interfaces = [ "wlan1" ];
};
};
testScript = ''
+ wpa_cli = "sudo -u nobody -g wpa_supplicant wpa_cli"
+
with subtest("Daemon is running and accepting connections"):
machine.wait_for_unit("wpa_supplicant-wlan1.service")
- status = machine.wait_until_succeeds("wpa_cli -i wlan1 status")
+ status = machine.wait_until_succeeds(f"{wpa_cli} -i wlan1 status")
assert "Failed to connect" not in status, \
"Failed to connect to the daemon"
with subtest("Daemon can be configured imperatively"):
- machine.succeed("wpa_cli -i wlan1 add_network")
- machine.succeed("wpa_cli -i wlan1 set_network 0 ssid '\"nixos-test\"'")
- machine.succeed("wpa_cli -i wlan1 set_network 0 psk '\"reproducibility\"'")
- machine.succeed("wpa_cli -i wlan1 save_config")
- machine.succeed("grep -q nixos-test /etc/wpa_supplicant.conf")
+ machine.succeed(f"{wpa_cli} -i wlan1 add_network")
+ machine.succeed(f"{wpa_cli} -i wlan1 set_network 0 ssid '\"nixos-test\"'")
+ machine.succeed(f"{wpa_cli} -i wlan1 set_network 0 psk '\"reproducibility\"'")
+ machine.succeed(f"{wpa_cli} -i wlan1 save_config")
+ machine.succeed("grep -q nixos-test /etc/wpa_supplicant/imperative.conf")
'';
};
diff --git a/pkgs/os-specific/linux/wpa_supplicant/default.nix b/pkgs/os-specific/linux/wpa_supplicant/default.nix
index 204481e0c0960..91377303c2298 100644
--- a/pkgs/os-specific/linux/wpa_supplicant/default.nix
+++ b/pkgs/os-specific/linux/wpa_supplicant/default.nix
@@ -14,6 +14,7 @@
readline,
withPcsclite ? !stdenv.hostPlatform.isStatic,
pcsclite,
+ unprivileged ? true,
}:
stdenv.mkDerivation rec {
@@ -33,8 +34,6 @@ stdenv.mkDerivation rec {
hash = "sha256-X6mBbj7BkW66aYeSCiI3JKBJv10etLQxaTRfRgwsFmM=";
revert = true;
})
- ./unsurprising-ext-password.patch
- ./multiple-configs.patch
(fetchpatch {
name = "suppress-ctrl-event-signal-change.patch";
url = "https://w1.fi/cgit/hostap/patch/?id=c330b5820eefa8e703dbce7278c2a62d9c69166a";
@@ -45,7 +44,10 @@ stdenv.mkDerivation rec {
url = "https://git.w1.fi/cgit/hostap/patch/?id=1ce37105da371c8b9cf3f349f78f5aac77d40836";
hash = "sha256-leCk0oexNBZyVK5Q5gR4ZcgWxa0/xt/aU+DssTa0UwE=";
})
- ];
+ ./unsurprising-ext-password.patch
+ ./multiple-configs.patch
+ ]
+ ++ lib.optional unprivileged ./unprivileged-daemon.patch;
# TODO: Patch epoll so that the dbus actually responds
# TODO: Figure out how to get privsep working, currently getting SIGBUS
diff --git a/pkgs/os-specific/linux/wpa_supplicant/unprivileged-daemon.patch b/pkgs/os-specific/linux/wpa_supplicant/unprivileged-daemon.patch
new file mode 100644
index 0000000000000..93dceff753cd6
--- /dev/null
+++ b/pkgs/os-specific/linux/wpa_supplicant/unprivileged-daemon.patch
@@ -0,0 +1,96 @@
+commit 24e932357ee3041763135b931206dfc0bbe0441e
+Author: rnhmjoj
+Date: Wed Jul 23 10:18:55 2025 +0200
+
+ Fixes for running wpa_supplicant unprivileged
+
+ 1. Change the dbus service user to "wpa_supplicant"
+
+ 2. Ensure appropriate group ownership and permissions on the client sockets.
+ Motivation: clients communicate with the daemon by creating "client"
+ sockets; by default this is owned by the user running the client,
+ so it may be inaccessible by the daemon.
+
+ 3. Move the "control" sockets under a subdirectory of /run/wpa_supplicant.
+ Motivation: wpa_supplicant will try to adjust the ownership of the
+ sockets directory, even if they are fine, and fail.
+
+ 4. Move the "client" under a subdirectory of /run/wpa_supplicant instead
+ of tmp. Motivation: this allows to unshare /tmp
+
+diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c
+index 7e197f0..6bfb091 100644
+--- a/src/common/wpa_ctrl.c
++++ b/src/common/wpa_ctrl.c
+@@ -15,6 +15,8 @@
+ #include
+ #include
+ #include
++#include
++#include
+ #include
+ #endif /* CONFIG_CTRL_IFACE_UNIX */
+ #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+@@ -165,6 +167,14 @@ try_again:
+ return NULL;
+ }
+
++ /* Set the client socket owner group to "wpa_supplicant"
++ * and ensure group and user permissions are the same */
++ struct group *grp = getgrnam("wpa_supplicant");
++ if (grp != NULL) {
++ lchown(ctrl->local.sun_path, -1, grp->gr_gid);
++ chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
++ }
++
+ #ifdef ANDROID
+ /* Set group even if we do not have privileges to change owner */
+ lchown(ctrl->local.sun_path, -1, AID_WIFI);
+--- a/wpa_supplicant/dbus/dbus-wpa_supplicant.conf
++++ b/wpa_supplicant/dbus/dbus-wpa_supplicant.conf
+@@ -2,9 +2,15 @@
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+
+-
++
+
+-
++
++
++
++
++
++
++
+
+
+
+diff --git a/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in b/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in
+index d97ff39..367a7c6 100644
+--- a/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in
++++ b/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in
+@@ -1,5 +1,5 @@
+ [D-BUS Service]
+ Name=fi.w1.wpa_supplicant1
+ Exec=@BINDIR@/wpa_supplicant -u
+-User=root
++User=wpa_supplicant
+ SystemdService=wpa_supplicant.service
+diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
+index af00e79..840b307 100644
+--- a/wpa_supplicant/wpa_cli.c
++++ b/wpa_supplicant/wpa_cli.c
+@@ -44,10 +44,10 @@ static int wpa_cli_attached = 0;
+ static int wpa_cli_connected = -1;
+ static int wpa_cli_last_id = 0;
+ #ifndef CONFIG_CTRL_IFACE_DIR
+-#define CONFIG_CTRL_IFACE_DIR "/var/run/wpa_supplicant"
++#define CONFIG_CTRL_IFACE_DIR "/run/wpa_supplicant/control"
+ #endif /* CONFIG_CTRL_IFACE_DIR */
+ static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
+-static const char *client_socket_dir = NULL;
++static const char *client_socket_dir = "/run/wpa_supplicant/client";
+ static char *ctrl_ifname = NULL;
+ static const char *global = NULL;
+ static const char *pid_file = NULL;