python3Packages.orjson: Disable failing tests on 32 bit
[NixPkgs.git] / nixos / modules / services / networking / supplicant.nix
blob0a48e73932e82144f80b788ef820145ba2b73878
1 { config, lib, utils, pkgs, ... }:
3 with lib;
5 let
7   cfg = config.networking.supplicant;
9   # We must escape interfaces due to the systemd interpretation
10   subsystemDevice = interface:
11     "sys-subsystem-net-devices-${utils.escapeSystemdPath interface}.device";
13   serviceName = iface: "supplicant-${if (iface=="WLAN") then "wlan@" else (
14                                      if (iface=="LAN") then "lan@" else (
15                                      if (iface=="DBUS") then "dbus"
16                                      else (replaceChars [" "] ["-"] iface)))}";
18   # TODO: Use proper privilege separation for wpa_supplicant
19   supplicantService = iface: suppl:
20     let
21       deps = (if (iface=="WLAN"||iface=="LAN") then ["sys-subsystem-net-devices-%i.device"] else (
22              if (iface=="DBUS") then ["dbus.service"]
23              else (map subsystemDevice (splitString " " iface))))
24              ++ optional (suppl.bridge!="") (subsystemDevice suppl.bridge);
26       ifaceArg = concatStringsSep " -N " (map (i: "-i${i}") (splitString " " iface));
27       driverArg = optionalString (suppl.driver != null) "-D${suppl.driver}";
28       bridgeArg = optionalString (suppl.bridge!="") "-b${suppl.bridge}";
29       confFileArg = optionalString (suppl.configFile.path!=null) "-c${suppl.configFile.path}";
30       extraConfFile = pkgs.writeText "supplicant-extra-conf-${replaceChars [" "] ["-"] iface}" ''
31         ${optionalString suppl.userControlled.enable "ctrl_interface=DIR=${suppl.userControlled.socketDir} GROUP=${suppl.userControlled.group}"}
32         ${optionalString suppl.configFile.writable "update_config=1"}
33         ${suppl.extraConf}
34       '';
35     in
36       { description = "Supplicant ${iface}${optionalString (iface=="WLAN"||iface=="LAN") " %I"}";
37         wantedBy = [ "multi-user.target" ] ++ deps;
38         wants = [ "network.target" ];
39         bindsTo = deps;
40         after = deps;
41         before = [ "network.target" ];
43         path = [ pkgs.coreutils ];
45         preStart = ''
46           ${optionalString (suppl.configFile.path!=null && suppl.configFile.writable) ''
47             (umask 077 && touch -a "${suppl.configFile.path}")
48           ''}
49           ${optionalString suppl.userControlled.enable ''
50             install -dm770 -g "${suppl.userControlled.group}" "${suppl.userControlled.socketDir}"
51           ''}
52         '';
54         serviceConfig.ExecStart = "${pkgs.wpa_supplicant}/bin/wpa_supplicant -s ${driverArg} ${confFileArg} -I${extraConfFile} ${bridgeArg} ${suppl.extraCmdArgs} ${if (iface=="WLAN"||iface=="LAN") then "-i%I" else (if (iface=="DBUS") then "-u" else ifaceArg)}";
56       };
63   ###### interface
65   options = {
67     networking.supplicant = mkOption {
68       type = with types; attrsOf (submodule {
69         options = {
71           configFile = {
73             path = mkOption {
74               type = types.nullOr types.path;
75               default = null;
76               example = literalExpression "/etc/wpa_supplicant.conf";
77               description = lib.mdDoc ''
78                 External `wpa_supplicant.conf` configuration file.
79                 The configuration options defined declaratively within `networking.supplicant` have
80                 precedence over options defined in `configFile`.
81               '';
82             };
84             writable = mkOption {
85               type = types.bool;
86               default = false;
87               description = lib.mdDoc ''
88                 Whether the configuration file at `configFile.path` should be written to by
89                 `wpa_supplicant`.
90               '';
91             };
93           };
95           extraConf = mkOption {
96             type = types.lines;
97             default = "";
98             example = ''
99               ap_scan=1
100               device_name=My-NixOS-Device
101               device_type=1-0050F204-1
102               driver_param=use_p2p_group_interface=1
103               disable_scan_offload=1
104               p2p_listen_reg_class=81
105               p2p_listen_channel=1
106               p2p_oper_reg_class=81
107               p2p_oper_channel=1
108               manufacturer=NixOS
109               model_name=NixOS_Unstable
110               model_number=2015
111             '';
112             description = lib.mdDoc ''
113               Configuration options for `wpa_supplicant.conf`.
114               Options defined here have precedence over options in `configFile`.
115               NOTE: Do not write sensitive data into `extraConf` as it will
116               be world-readable in the `nix-store`. For sensitive information
117               use the `configFile` instead.
118             '';
119           };
121           extraCmdArgs = mkOption {
122             type = types.str;
123             default = "";
124             example = "-e/run/wpa_supplicant/entropy.bin";
125             description =
126               lib.mdDoc "Command line arguments to add when executing `wpa_supplicant`.";
127           };
129           driver = mkOption {
130             type = types.nullOr types.str;
131             default = "nl80211,wext";
132             description = lib.mdDoc "Force a specific wpa_supplicant driver.";
133           };
135           bridge = mkOption {
136             type = types.str;
137             default = "";
138             description = lib.mdDoc "Name of the bridge interface that wpa_supplicant should listen at.";
139           };
141           userControlled = {
143             enable = mkOption {
144               type = types.bool;
145               default = false;
146               description = lib.mdDoc ''
147                 Allow normal users to control wpa_supplicant through wpa_gui or wpa_cli.
148                 This is useful for laptop users that switch networks a lot and don't want
149                 to depend on a large package such as NetworkManager just to pick nearby
150                 access points.
151               '';
152             };
154             socketDir = mkOption {
155               type = types.str;
156               default = "/run/wpa_supplicant";
157               description = lib.mdDoc "Directory of sockets for controlling wpa_supplicant.";
158             };
160             group = mkOption {
161               type = types.str;
162               default = "wheel";
163               example = "network";
164               description = lib.mdDoc "Members of this group can control wpa_supplicant.";
165             };
167           };
168         };
169       });
171       default = { };
173       example = literalExpression ''
174         { "wlan0 wlan1" = {
175             configFile.path = "/etc/wpa_supplicant.conf";
176             userControlled.group = "network";
177             extraConf = '''
178               ap_scan=1
179               p2p_disabled=1
180             ''';
181             extraCmdArgs = "-u -W";
182             bridge = "br0";
183           };
184         }
185       '';
187       description = lib.mdDoc ''
188         Interfaces for which to start {command}`wpa_supplicant`.
189         The supplicant is used to scan for and associate with wireless networks,
190         or to authenticate with 802.1x capable network switches.
192         The value of this option is an attribute set. Each attribute configures a
193         {command}`wpa_supplicant` service, where the attribute name specifies
194         the name of the interface that {command}`wpa_supplicant` operates on.
195         The attribute name can be a space separated list of interfaces.
196         The attribute names `WLAN`, `LAN` and `DBUS`
197         have a special meaning. `WLAN` and `LAN` are
198         configurations for universal {command}`wpa_supplicant` service that is
199         started for each WLAN interface or for each LAN interface, respectively.
200         `DBUS` defines a device-unrelated {command}`wpa_supplicant`
201         service that can be accessed through `D-Bus`.
202       '';
204     };
206   };
209   ###### implementation
211   config = mkIf (cfg != {}) {
213     environment.systemPackages =  [ pkgs.wpa_supplicant ];
215     services.dbus.packages = [ pkgs.wpa_supplicant ];
217     systemd.services = mapAttrs' (n: v: nameValuePair (serviceName n) (supplicantService n v)) cfg;
219     services.udev.packages = [
220       (pkgs.writeTextFile {
221         name = "99-zzz-60-supplicant.rules";
222         destination = "/etc/udev/rules.d/99-zzz-60-supplicant.rules";
223         text = ''
224           ${flip (concatMapStringsSep "\n") (filter (n: n!="WLAN" && n!="LAN" && n!="DBUS") (attrNames cfg)) (iface:
225             flip (concatMapStringsSep "\n") (splitString " " iface) (i: ''
226               ACTION=="add", SUBSYSTEM=="net", ENV{INTERFACE}=="${i}", TAG+="systemd", ENV{SYSTEMD_WANTS}+="supplicant-${replaceChars [" "] ["-"] iface}.service", TAG+="SUPPLICANT_ASSIGNED"''))}
228           ${optionalString (hasAttr "WLAN" cfg) ''
229             ACTION=="add", SUBSYSTEM=="net", ENV{DEVTYPE}=="wlan", TAG!="SUPPLICANT_ASSIGNED", TAG+="systemd", PROGRAM="/run/current-system/systemd/bin/systemd-escape -p %E{INTERFACE}", ENV{SYSTEMD_WANTS}+="supplicant-wlan@$result.service"
230           ''}
231           ${optionalString (hasAttr "LAN" cfg) ''
232             ACTION=="add", SUBSYSTEM=="net", ENV{DEVTYPE}=="lan", TAG!="SUPPLICANT_ASSIGNED", TAG+="systemd", PROGRAM="/run/current-system/systemd/bin/systemd-escape -p %E{INTERFACE}", ENV{SYSTEMD_WANTS}+="supplicant-lan@$result.service"
233           ''}
234         '';
235       })];
237   };