diff --git a/modules/hardware/network/b43.nix b/modules/hardware/network/b43.nix index 077e0a1e11e..8f45bd4d3f1 100644 --- a/modules/hardware/network/b43.nix +++ b/modules/hardware/network/b43.nix @@ -22,9 +22,11 @@ let kernelVersion = config.boot.kernelPackages.kernel.version; in ###### implementation config = pkgs.lib.mkIf config.networking.enableB43Firmware { - hardware.firmware = if builtins.lessThan (builtins.compareVersions kernelVersion "3.2") 0 then - throw "b43 firmware for kernels older than 3.2 not packaged yet!" else - [ pkgs.b43Firmware_5_1_138 ]; + assertions = [ { + assertion = builtins.lessThan 0 (builtins.compareVersions kernelVersion "3.2"); + message = "b43 firmware for kernels older than 3.2 not packaged yet!"; + } ]; + hardware.firmware = [ pkgs.b43Firmware_5_1_138 ]; }; } diff --git a/modules/misc/ids.nix b/modules/misc/ids.nix index e466aff16a8..61cf4be0426 100644 --- a/modules/misc/ids.nix +++ b/modules/misc/ids.nix @@ -73,6 +73,7 @@ in fprot = 52; bind = 53; wwwrun = 54; + spamd = 55; # When adding a uid, make sure it doesn't match an existing gid. diff --git a/modules/module-list.nix b/modules/module-list.nix index 8c5ffff8b27..3d3f5b94731 100644 --- a/modules/module-list.nix +++ b/modules/module-list.nix @@ -77,6 +77,7 @@ ./services/hardware/udisks.nix ./services/hardware/upower.nix #./services/logging/klogd.nix + ./services/logging/logcheck.nix ./services/logging/logrotate.nix ./services/logging/logstash.nix ./services/logging/syslogd.nix diff --git a/modules/services/logging/logcheck.nix b/modules/services/logging/logcheck.nix new file mode 100644 index 00000000000..40d736255ec --- /dev/null +++ b/modules/services/logging/logcheck.nix @@ -0,0 +1,139 @@ +{config, pkgs, ...}: + +with pkgs.lib; + +let + cfg = config.services.logcheck; + + rulesDir = pkgs.runCommand "logcheck-rules-dir" + {} ( + '' + mkdir $out + cp -prd ${pkgs.logcheck}/etc/logcheck/* $out/ + rm $out/logcheck.* + chmod u+w $out/* + '' + optionalString (! builtins.isNull cfg.extraRulesDir) '' + cp -prd ${cfg.extraRulesDir}/* $out/ + '' ); + + configFile = pkgs.writeText "logcheck.conf" cfg.config; + + logFiles = pkgs.writeText "logcheck.logfiles" cfg.files; + + flags = "-r ${rulesDir} -c ${configFile} -L ${logFiles} -${levelFlag} -m ${cfg.mailTo}"; + + levelFlag = getAttrFromPath [cfg.level] + { "paranoid" = "p"; + "server" = "s"; + "workstation" = "w"; + }; + + cronJob = '' + @reboot logcheck env PATH=/var/setuid-wrappers:$PATH nice -n10 ${pkgs.logcheck}/sbin/logcheck -R ${flags} + 2 ${cfg.timeOfDay} * * * logcheck env PATH=/var/setuid-wrappers:$PATH nice -n10 ${pkgs.logcheck}/sbin/logcheck ${flags} + ''; + +in +{ + options = { + services.logcheck = { + enable = mkOption { + default = false; + type = types.bool; + description = '' + Enable the logcheck cron job. + ''; + }; + + user = mkOption { + default = "logcheck"; + type = types.uniq types.string; + description = '' + Username for the logcheck user. + ''; + }; + + timeOfDay = mkOption { + default = "*"; + example = "6"; + type = types.uniq types.string; + description = '' + Time of day to run logcheck. A logcheck will be scheduled at xx:02 each day. + Leave default (*) to run every hour. Of course when nothing special was logged, + logcheck will be silent. + ''; + }; + + mailTo = mkOption { + default = "root"; + example = "you@domain.com"; + type = types.uniq types.string; + description = '' + Email address to send reports to. + ''; + }; + + level = mkOption { + default = "server"; + type = types.uniq types.string; + description = '' + Set the logcheck level. Either "workstation", "server", or "paranoid". + ''; + }; + + config = mkOption { + default = "FQDN=1"; + type = types.string; + description = '' + Config options that you would like in logcheck.conf. + ''; + }; + + files = mkOption { + default = [ "/var/log/messages" ]; + type = types.listOf types.path; + example = [ "/var/log/messages" "/var/log/mail" ]; + description = '' + Which log files to check. + ''; + }; + + extraRulesDir = mkOption { + default = null; + example = "/etc/logcheck"; + type = types.nullOr types.path; + description = '' + Directory with extra rules. + Will be merged with bundled rules, so it's possible to override certain behaviour. + ''; + }; + + extraGroups = mkOption { + default = []; + type = types.listOf types.string; + example = [ "postdrop" "mongodb" ]; + description = '' + Extra groups for the logcheck user, for example to be able to use sendmail, + or to access certain log files. + ''; + }; + + }; + }; + + config = mkIf cfg.enable { + users.extraUsers = singleton + { name = cfg.user; + shell = "/bin/sh"; + description = "Logcheck user account"; + extraGroups = cfg.extraGroups; + }; + + system.activationScripts.logcheck = '' + mkdir -m 700 -p /var/{lib,lock}/logcheck + chown ${cfg.user} /var/{lib,lock}/logcheck + ''; + + services.cron.systemCronJobs = [ cronJob ]; + }; +} diff --git a/modules/services/logging/logstash.nix b/modules/services/logging/logstash.nix index bb3b83dd230..f4c226ac349 100644 --- a/modules/services/logging/logstash.nix +++ b/modules/services/logging/logstash.nix @@ -141,6 +141,7 @@ in jobs.logstash = with pkgs; { description = "Logstash daemon"; + startOn = "started networking and filesystem"; path = [ jre ]; diff --git a/modules/services/mail/postfix.nix b/modules/services/mail/postfix.nix index 842427f6d05..3784ae3d39f 100644 --- a/modules/services/mail/postfix.nix +++ b/modules/services/mail/postfix.nix @@ -80,6 +80,9 @@ let recipientDelimiter = ${cfg.recipientDelimiter} '' + + optionalString (cfg.virtual != "") '' + virtual_alias_maps = hash:/etc/postfix/virtual + '' + cfg.extraConfig; aliases = @@ -93,6 +96,7 @@ let ; aliasesFile = pkgs.writeText "postfix-aliases" aliases; + virtualFile = pkgs.writeText "postfix-virtual" cfg.virtual; mainCfFile = pkgs.writeText "postfix-main.cf" mainCf; in @@ -255,6 +259,13 @@ in "; }; + virtual = mkOption { + default = ""; + description = " + Entries for the virtual alias map. + "; + }; + }; }; @@ -338,9 +349,11 @@ in ln -sf ${pkgs.postfix}/share/postfix/conf/* /var/postfix/conf ln -sf ${aliasesFile} /var/postfix/conf/aliases + ln -sf ${virtualFile} /var/postfix/conf/virtual ln -sf ${mainCfFile} /var/postfix/conf/main.cf ${pkgs.postfix}/sbin/postalias -c /var/postfix/conf /var/postfix/conf/aliases + ${pkgs.postfix}/sbin/postmap -c /var/postfix/conf /var/postfix/conf/virtual exec ${pkgs.postfix}/sbin/postfix -c /var/postfix/conf start ''; # */ diff --git a/modules/services/mail/spamassassin.nix b/modules/services/mail/spamassassin.nix index 69d3c390bc9..9b387eb940f 100644 --- a/modules/services/mail/spamassassin.nix +++ b/modules/services/mail/spamassassin.nix @@ -33,11 +33,17 @@ in # Allow users to run 'spamc'. environment.systemPackages = [ pkgs.spamassassin ]; + users.extraUsers = singleton + { name = "spamd"; + description = "Spam Assassin Daemon"; + uid = config.ids.uids.spamd; + }; + jobs.spamd = { description = "Spam Assassin Server"; startOn = "started networking and filesystem"; environment.TZ = config.time.timeZone; - exec = "${pkgs.spamassassin}/bin/spamd -C /etc/spamassassin/init.pre --siteconfigpath=/etc/spamassassin --debug --pidfile=/var/run/spamd.pid"; + exec = "${pkgs.spamassassin}/bin/spamd -C /etc/spamassassin/init.pre --siteconfigpath=/etc/spamassassin --username=spamd --pidfile=/var/run/spamd.pid"; }; }; diff --git a/modules/services/networking/avahi-daemon.nix b/modules/services/networking/avahi-daemon.nix index 791109dcda2..3603d677837 100644 --- a/modules/services/networking/avahi-daemon.nix +++ b/modules/services/networking/avahi-daemon.nix @@ -11,7 +11,13 @@ let avahiDaemonConf = with cfg; pkgs.writeText "avahi-daemon.conf" '' [server] - host-name=${hostName} + ${# Users can set `networking.hostName' to the empty string, when getting + # a host name from DHCP. In that case, let Avahi take whatever the + # current host name is; setting `host-name' to the empty string in + # `avahi-daemon.conf' would be invalid. + if hostName != "" + then "host-name=${hostName}" + else ""} browse-domains=${concatStringsSep ", " browseDomains} use-ipv4=${if ipv4 then "yes" else "no"} use-ipv6=${if ipv6 then "yes" else "no"} diff --git a/modules/system/boot/stage-1.nix b/modules/system/boot/stage-1.nix index 4f41aa4badc..97f1aa516e8 100644 --- a/modules/system/boot/stage-1.nix +++ b/modules/system/boot/stage-1.nix @@ -123,6 +123,20 @@ let enableSplashScreen = config.boot.vesa && config.boot.initrd.enableSplashScreen && kernelPackages.splashutils != null; + needsCifsUtils = kernelPackages.kernel ? features + && kernelPackages.kernel.features ? needsCifsUtils + && kernelPackages.kernel.features.needsCifsUtils + && any (fs: fs.fsType == "cifs") fileSystems; + + busybox = if needsCifsUtils + then pkgs.busybox.override { + extraConfig = '' + CONFIG_FEATURE_MOUNT_CIFS n + CONFIG_FEATURE_MOUNT_HELPERS y + ''; + } + else pkgs.busybox; + # Some additional utilities needed in stage 1, like mount, lvm, fsck # etc. We don't want to bring in all of those packages, so we just @@ -148,7 +162,7 @@ let cp -pv ${pkgs.gcc.gcc}/lib*/libgcc_s.so.* $out/lib # Copy BusyBox. - cp -rvd ${pkgs.busybox}/{bin,sbin} $out/ + cp -rvd ${busybox}/{bin,sbin} $out/ chmod -R u+w $out # Copy some utillinux stuff. @@ -180,6 +194,11 @@ let cp ${kernelPackages.splashutils}/${kernelPackages.splashutils.helperName} $out/bin/splash_helper ''} + # Maybe copy cifs utils + ${optionalString needsCifsUtils '' + cp -v ${pkgs.cifs_utils}/sbin/mount.cifs $out/bin + ''} + ${config.boot.initrd.extraUtilsCommands} # Strip binaries further than normal. diff --git a/modules/system/boot/stage-2-init.sh b/modules/system/boot/stage-2-init.sh index e4522c56775..79d332690b9 100644 --- a/modules/system/boot/stage-2-init.sh +++ b/modules/system/boot/stage-2-init.sh @@ -121,7 +121,7 @@ if ! mountpoint -q /run; then mount -t tmpfs -o "mode=0755,size=@runSize@" none /run fi -mkdir -m 0700 -p /run/lock +mkdir -m 0755 -p /run/lock # For backwards compatibility, symlink /var/run to /run, and /var/lock diff --git a/modules/tasks/network-interfaces.nix b/modules/tasks/network-interfaces.nix index 5302fa82bd4..a6fffce5bf4 100644 --- a/modules/tasks/network-interfaces.nix +++ b/modules/tasks/network-interfaces.nix @@ -5,6 +5,7 @@ with pkgs.lib; let cfg = config.networking; + hasVirtuals = any (i: i.virtual) cfg.interfaces; in @@ -119,6 +120,44 @@ in ''; }; + virtual = mkOption { + default = false; + type = types.bool; + description = '' + Whether this interface is virtual and should be created by tunctl. + This is mainly useful for creating bridges between a host a virtual + network such as VPN or a virtual machine. + + Defaults to tap device, unless interface contains "tun" in its name. + ''; + }; + + virtualOwner = mkOption { + default = "root"; + type = types.uniq types.string; + description = '' + In case of a virtual device, the user who owns it. + ''; + }; + + proxyARP = mkOption { + default = false; + type = types.bool; + description = '' + Turn on proxy_arp for this device (and proxy_ndp for ipv6). + This is mainly useful for creating pseudo-bridges between a real + interface and a virtual network such as VPN or a virtual machine for + interfaces that don't support real bridging (most wlan interfaces). + As ARP proxying acts slightly above the link-layer, below-ip traffic + isn't bridged, so things like DHCP won't work. The advantage above + using NAT lies in the fact that no IP addresses are shared, so all + hosts are reachable/routeable. + + WARNING: turns on ip-routing, so if you have multiple interfaces, you + should think of the consequence and setup firewall rules to limit this. + ''; + }; + }; }; @@ -179,7 +218,7 @@ in config = { - boot.kernelModules = optional cfg.enableIPv6 "ipv6"; + boot.kernelModules = optional cfg.enableIPv6 "ipv6" ++ optional hasVirtuals "tun"; environment.systemPackages = [ pkgs.host @@ -191,6 +230,7 @@ in pkgs.openresolv ] ++ optional (cfg.bridges != {}) pkgs.bridge_utils + ++ optional hasVirtuals pkgs.tunctl ++ optional cfg.enableIPv6 pkgs.ndisc6; security.setuidPrograms = [ "ping" "ping6" ]; @@ -208,6 +248,15 @@ in '' set +e # continue in case of errors + # Create virtual network interfaces + ${flip concatMapStrings cfg.interfaces (i: + optionalString i.virtual + '' + echo "Creating virtual network interface ${i.name}..." + ${pkgs.tunctl}/bin/tunctl -t "${i.name}" -u "${i.virtualOwner}" + '') + } + # Set MAC addresses of interfaces, if desired. ${flip concatMapStrings cfg.interfaces (i: optionalString (i.macAddress != "") @@ -246,6 +295,14 @@ in echo "Configuring interface ${i.name}..." ip addr add "${i.ipAddress}""${optionalString (i.subnetMask != "") ("/" + i.subnetMask)}" \ dev "${i.name}" + '' + + optionalString i.proxyARP + '' + echo 1 > /proc/sys/net/ipv4/conf/${i.name}/proxy_arp + '' + + optionalString (i.proxyARP && cfg.enableIPv6) + '' + echo 1 > /proc/sys/net/ipv6/conf/${i.name}/proxy_ndp '') } @@ -264,6 +321,11 @@ in ip route add default via "${cfg.defaultGateway}" ''} + # turn on forwarding if any interface has enabled proxy_arp + ${optionalString (any (i: i.proxyARP) cfg.interfaces) '' + echo 1 > /proc/sys/net/ipv4/ip_forward + ''} + # Run any user-specified commands. ${pkgs.stdenv.shell} ${pkgs.writeText "local-net-cmds" cfg.localCommands}