vuls: init at 0.27.0
[NixPkgs.git] / nixos / modules / services / networking / supplicant.nix
blob52645500d4f6adaee2870f4cd99d84adbe4f2a40
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 (replaceStrings [" "] ["-"] 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-${replaceStrings [" "] ["-"] 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 = ''
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 = ''
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 = ''
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 = "Command line arguments to add when executing `wpa_supplicant`.";
126           };
128           driver = mkOption {
129             type = types.nullOr types.str;
130             default = "nl80211,wext";
131             description = "Force a specific wpa_supplicant driver.";
132           };
134           bridge = mkOption {
135             type = types.str;
136             default = "";
137             description = "Name of the bridge interface that wpa_supplicant should listen at.";
138           };
140           userControlled = {
142             enable = mkOption {
143               type = types.bool;
144               default = false;
145               description = ''
146                 Allow normal users to control wpa_supplicant through wpa_gui or wpa_cli.
147                 This is useful for laptop users that switch networks a lot and don't want
148                 to depend on a large package such as NetworkManager just to pick nearby
149                 access points.
150               '';
151             };
153             socketDir = mkOption {
154               type = types.str;
155               default = "/run/wpa_supplicant";
156               description = "Directory of sockets for controlling wpa_supplicant.";
157             };
159             group = mkOption {
160               type = types.str;
161               default = "wheel";
162               example = "network";
163               description = "Members of this group can control wpa_supplicant.";
164             };
166           };
167         };
168       });
170       default = { };
172       example = literalExpression ''
173         { "wlan0 wlan1" = {
174             configFile.path = "/etc/wpa_supplicant.conf";
175             userControlled.group = "network";
176             extraConf = '''
177               ap_scan=1
178               p2p_disabled=1
179             ''';
180             extraCmdArgs = "-u -W";
181             bridge = "br0";
182           };
183         }
184       '';
186       description = ''
187         Interfaces for which to start {command}`wpa_supplicant`.
188         The supplicant is used to scan for and associate with wireless networks,
189         or to authenticate with 802.1x capable network switches.
191         The value of this option is an attribute set. Each attribute configures a
192         {command}`wpa_supplicant` service, where the attribute name specifies
193         the name of the interface that {command}`wpa_supplicant` operates on.
194         The attribute name can be a space separated list of interfaces.
195         The attribute names `WLAN`, `LAN` and `DBUS`
196         have a special meaning. `WLAN` and `LAN` are
197         configurations for universal {command}`wpa_supplicant` service that is
198         started for each WLAN interface or for each LAN interface, respectively.
199         `DBUS` defines a device-unrelated {command}`wpa_supplicant`
200         service that can be accessed through `D-Bus`.
201       '';
203     };
205   };
208   ###### implementation
210   config = mkIf (cfg != {}) {
212     environment.systemPackages =  [ pkgs.wpa_supplicant ];
214     services.dbus.packages = [ pkgs.wpa_supplicant ];
216     systemd.services = mapAttrs' (n: v: nameValuePair (serviceName n) (supplicantService n v)) cfg;
218     services.udev.packages = [
219       (pkgs.writeTextFile {
220         name = "99-zzz-60-supplicant.rules";
221         destination = "/etc/udev/rules.d/99-zzz-60-supplicant.rules";
222         text = ''
223           ${flip (concatMapStringsSep "\n") (filter (n: n!="WLAN" && n!="LAN" && n!="DBUS") (attrNames cfg)) (iface:
224             flip (concatMapStringsSep "\n") (splitString " " iface) (i: ''
225               ACTION=="add", SUBSYSTEM=="net", ENV{INTERFACE}=="${i}", TAG+="systemd", ENV{SYSTEMD_WANTS}+="supplicant-${replaceStrings [" "] ["-"] iface}.service", TAG+="SUPPLICANT_ASSIGNED"''))}
227           ${optionalString (hasAttr "WLAN" cfg) ''
228             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"
229           ''}
230           ${optionalString (hasAttr "LAN" cfg) ''
231             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"
232           ''}
233         '';
234       })];
236   };