Merge remote-tracking branch 'origin/master' into systemd

This commit is contained in:
Eelco Dolstra 2012-11-30 16:12:04 +01:00
commit b1da38f564
28 changed files with 853 additions and 272 deletions

View file

@ -150,7 +150,7 @@ $ nixos-rebuild switch -I <replaceable>/my/sources</replaceable>
definitions. This conditional values can be distinguished in two
categories. The condition which are local to the current configuration
and conditions which are dependent on others configurations. Local
properties are <varname>mkIf</varname>, <varname>mkAlways</varname>
properties are <varname>mkIf</varname>
and <varname>mkAssert</varname>. Global properties
are <varname>mkOverride</varname>, <varname>mkDefault</varname>
and <varname>mkOrder</varname>.</para>
@ -158,12 +158,7 @@ $ nixos-rebuild switch -I <replaceable>/my/sources</replaceable>
<para><varname>mkIf</varname> is used to remove the option definitions which
are below it if the condition is evaluated to
false. <varname>mkAssert</varname> expects the condition to be evaluated
to true otherwise it raises an error message. <varname>mkAlways</varname>
is used to ignore all the <varname>mkIf</varname>
and <varname>mkAssert</varname> which have been made
previously. <varname>mkAlways</varname> and <varname>mkAssert</varname>
are often used together to set an option value and to ensure that it has
not been masked by another one.</para>
to true otherwise it raises an error message.</para>
<para><varname>mkOverride</varname> is used to mask previous definitions if
the current value has a lower mask number. The mask value is 100 (default)
@ -223,14 +218,6 @@ let
locatedb = "/var/cache/locatedb";
logfile = "/var/log/updatedb";
cmd =''root updatedb --localuser=nobody --output=${locatedb} > ${logfile}'';
mkCheck = x:
mkIf cfg.enable (
mkAssert config.services.cron.enable ''
The cron daemon is not enabled, required by services.locate.enable.
''
x
)
in
{
@ -260,9 +247,9 @@ in
};
};
config = mkCheck {
config = mkIf cfg.enable {
services.cron = {
enable = mkAlways cfg.enable;
enable = true;
systemCronJobs = "${cfg.period} root ${cmd}";
};
};

View file

@ -1,8 +1,13 @@
{pkgs, config, ...}:
with pkgs.lib;
with pkgs;
###### interface
let
inherit (pkgs.lib) mkOption mkIf optionalString stringAfter;
inherit mkOption mkIf optionalString stringAfter singleton;
cfg = config.users.ldap;
options = {
users = {
@ -41,7 +46,7 @@ let
timeLimit = mkOption {
default = 0;
type = with pkgs.lib.types; int;
type = types.int;
description = "
Specifies the time limit (in seconds) to use when performing
searches. A value of zero (0), which is the default, is to
@ -49,11 +54,36 @@ let
";
};
daemon = {
enable = mkOption {
default = false;
description = ''
Whether to let the nslcd daemon (nss-pam-ldapd) handle the
LDAP lookups for NSS and PAM. This can improve performance,
and if you need to bind to the LDAP server with a password,
it increases security, since only the nslcd user needs to
have access to the bindpw file, not everyone that uses NSS
and/or PAM. If this option is enabled, a local nscd user is
created automatically, and the nslcd service is started
automatically when the network get up.
'';
};
extraConfig = mkOption {
default = "";
type = types.string;
description = ''
Extra configuration options that will be added verbatim at
the end of the nslcd configuration file (nslcd.conf).
'' ;
} ;
};
bind = {
distinguishedName = mkOption {
default = "";
example = "cn=admin,dc=example,dc=com";
type = with pkgs.lib.types; string;
type = types.string;
description = "
The distinguished name to bind to the LDAP server with. If this
is not specified, an anonymous bind will be done.
@ -62,7 +92,7 @@ let
password = mkOption {
default = "/etc/ldap/bind.password";
type = with pkgs.lib.types; string;
type = types.string;
description = "
The path to a file containing the credentials to use when binding
to the LDAP server (if not binding anonymously).
@ -71,7 +101,7 @@ let
timeLimit = mkOption {
default = 30;
type = with pkgs.lib.types; int;
type = types.int;
description = "
Specifies the time limit (in seconds) to use when connecting
to the directory server. This is distinct from the time limit
@ -82,7 +112,7 @@ let
policy = mkOption {
default = "hard_open";
type = with pkgs.lib.types; string;
type = types.string;
description = "
Specifies the policy to use for reconnecting to an unavailable
LDAP server. The default is <literal>hard_open</literal>, which
@ -99,55 +129,120 @@ let
};
};
extraConfig = mkOption {
default = "" ;
type = types.string ;
description = ''
Extra configuration options that will be added verbatim at
the end of the ldap configuration file (ldap.conf).
If <literal>users.ldap.daemon</literal> is enabled, this
configuration will not be used. In that case, use
<literal>users.ldap.daemon.extraConfig</literal> instead.
'' ;
};
};
};
};
# Careful: OpenLDAP seems to be very picky about the indentation of
# this file. Directives HAVE to start in the first column!
ldapConfig = {
target = "ldap.conf";
source = writeText "ldap.conf" ''
uri ${config.users.ldap.server}
base ${config.users.ldap.base}
timelimit ${toString config.users.ldap.timeLimit}
bind_timelimit ${toString config.users.ldap.bind.timeLimit}
bind_policy ${config.users.ldap.bind.policy}
${optionalString config.users.ldap.useTLS ''
ssl start_tls
tls_checkpeer no
''}
${optionalString (config.users.ldap.bind.distinguishedName != "") ''
binddn ${config.users.ldap.bind.distinguishedName}
''}
${optionalString (cfg.extraConfig != "") cfg.extraConfig }
'';
};
nslcdConfig = {
target = "nslcd.conf";
source = writeText "nslcd.conf" ''
uid nslcd
gid nslcd
uri ${cfg.server}
base ${cfg.base}
timelimit ${toString cfg.timeLimit}
bind_timelimit ${toString cfg.bind.timeLimit}
${optionalString (cfg.bind.distinguishedName != "")
"binddn ${cfg.bind.distinguishedName}" }
${optionalString (cfg.daemon.extraConfig != "") cfg.daemon.extraConfig }
'';
};
insertLdapPassword = !config.users.ldap.daemon.enable &&
config.users.ldap.bind.distinguishedName != "";
in
###### implementation
mkIf config.users.ldap.enable {
mkIf cfg.enable {
require = [
options
];
# LDAP configuration.
environment = {
etc = [
environment.etc = if cfg.daemon.enable then [nslcdConfig] else [ldapConfig];
# Careful: OpenLDAP seems to be very picky about the indentation of
# this file. Directives HAVE to start in the first column!
{ source = pkgs.writeText "ldap.conf"
''
uri ${config.users.ldap.server}
base ${config.users.ldap.base}
timelimit ${toString config.users.ldap.timeLimit}
bind_timelimit ${toString config.users.ldap.bind.timeLimit}
bind_policy ${config.users.ldap.bind.policy}
${optionalString config.users.ldap.useTLS ''
ssl start_tls
tls_checkpeer no
''}
${optionalString (config.users.ldap.bind.distinguishedName != "") ''
binddn ${config.users.ldap.bind.distinguishedName}
''}
'';
target = "ldap.conf";
}
];
};
system.activationScripts.ldap = stringAfter [ "etc" ] (
optionalString (config.users.ldap.bind.distinguishedName != "") ''
if test -f "${config.users.ldap.bind.password}" ; then
echo "bindpw $(cat ${config.users.ldap.bind.password})" | cat /etc/ldap.conf - > /etc/ldap.conf.bindpw
system.activationScripts = mkIf insertLdapPassword {
ldap = stringAfter [ "etc" "groups" "users" ] ''
if test -f "${cfg.bind.password}" ; then
echo "bindpw "$(cat ${cfg.bind.password})"" | cat ${ldapConfig} - > /etc/ldap.conf.bindpw
mv -fT /etc/ldap.conf.bindpw /etc/ldap.conf
chmod 600 /etc/ldap.conf
fi
''
'';
};
system.nssModules = singleton (
if cfg.daemon.enable then nss_pam_ldapd else nss_ldap
);
users = mkIf cfg.daemon.enable {
extraGroups.nslcd = {
gid = config.ids.gids.nslcd;
};
extraUsers.nslcd = {
uid = config.ids.uids.nslcd;
description = "nslcd user.";
group = "nslcd";
};
};
jobs = mkIf cfg.daemon.enable {
nslcd = {
startOn = "filesystem";
stopOn = "stopping network-interfaces";
daemonType = "fork";
path = [ nss_pam_ldapd ];
preStart = ''
mkdir -p /run/nslcd
chown nslcd.nslcd /run/nslcd
${optionalString (cfg.bind.distinguishedName != "") ''
if test -s "${cfg.bind.password}" ; then
ln -sfT "${cfg.bind.password}" /run/nslcd/bindpw
fi
''}
'';
postStop = "rm -f /run/nslcd/nslcd.pid";
exec = "nslcd";
};
};
}

View file

@ -18,6 +18,18 @@ let
'';
};
networking.dnsSingleRequest = pkgs.lib.mkOption {
default = false;
description = ''
Recent versions of glibc will issue both ipv4 (A) and ipv6 (AAAA)
address queries at the same time, from the same port. Sometimes upstream
routers will systemically drop the ipv4 queries. The symptom of this problem is
that 'getent hosts example.com' only returns ipv6 (or perhaps only ipv4) addresses. The
workaround for this is to specify the option 'single-request' in
/etc/resolve.conf. This option enables that.
'';
};
};
in
@ -64,6 +76,9 @@ in
# Invalidate the nscd cache whenever resolv.conf is
# regenerated.
libc_restart='${pkgs.systemd}/bin/systemctl reload --no-block nscd.service'
'' + optionalString cfg.dnsSingleRequest ''
# only send one DNS request at a time
resolv_conf_options='single-request'
'' + optionalString config.services.bind.enable ''
# This hosts runs a full-blown DNS resolver.
name_servers='127.0.0.1'

View file

@ -19,14 +19,9 @@ let
";
merge = mergeListOption;
apply = list:
let
list2 =
list
# !!! this should be in the LDAP module
++ optional config.users.ldap.enable pkgs.nss_ldap;
in {
list = list2;
path = makeLibraryPath list2;
{
inherit list;
path = makeLibraryPath list;
};
};

View file

@ -28,64 +28,65 @@ let cfg = config.hardware.pulseaudio; in
};
config = mkIf cfg.enable {
config = mkMerge
[ # Create pulse/client.conf even if PulseAudio is disabled so
# that we can disable the autospawn feature in programs that
# are built with PulseAudio support (like KDE).
{ environment.etc = singleton
{ target = "pulse/client.conf";
source = pkgs.writeText "client.conf"
''
autospawn=${if cfg.enable then "yes" else "no"}
${optionalString cfg.enable ''
daemon-binary=${cfg.package}/bin/pulseaudio
''}
'';
};
}
environment.systemPackages =
[ cfg.package ];
(mkIf cfg.enable {
environment.etc = mkAlways (
[ # Create pulse/client.conf even if PulseAudio is disabled so
# that we can disable the autospawn feature in programs that
# are built with PulseAudio support (like KDE).
{ target = "pulse/client.conf";
source = pkgs.writeText "client.conf"
''
autospawn=${if cfg.enable then "yes" else "no"}
${optionalString cfg.enable ''
daemon-binary=${cfg.package}/bin/pulseaudio
''}
'';
}
environment.systemPackages = [ cfg.package ];
] ++ optionals cfg.enable
[ # Write an /etc/asound.conf that causes all ALSA applications to
# be re-routed to the PulseAudio server through ALSA's Pulse
# plugin.
{ target = "asound.conf";
source = pkgs.writeText "asound.conf"
''
pcm_type.pulse {
lib ${pkgs.alsaPlugins}/lib/alsa-lib/libasound_module_pcm_pulse.so
}
environment.etc =
[ # Write an /etc/asound.conf that causes all ALSA applications to
# be re-routed to the PulseAudio server through ALSA's Pulse
# plugin.
{ target = "asound.conf";
source = pkgs.writeText "asound.conf"
''
pcm_type.pulse {
lib ${pkgs.alsaPlugins}/lib/alsa-lib/libasound_module_pcm_pulse.so
}
pcm.!default {
type pulse
hint.description "Default Audio Device (via PulseAudio)"
}
pcm.!default {
type pulse
hint.description "Default Audio Device (via PulseAudio)"
}
ctl_type.pulse {
lib ${pkgs.alsaPlugins}/lib/alsa-lib/libasound_module_ctl_pulse.so
}
ctl_type.pulse {
lib ${pkgs.alsaPlugins}/lib/alsa-lib/libasound_module_ctl_pulse.so
}
ctl.!default {
type pulse
}
'';
}
ctl.!default {
type pulse
}
'';
}
{ target = "pulse/default.pa";
source = "${cfg.package}/etc/pulse/default.pa";
}
{ target = "pulse/default.pa";
source = "${cfg.package}/etc/pulse/default.pa";
}
{ target = "pulse/system.pa";
source = "${cfg.package}/etc/pulse/system.pa";
}
{ target = "pulse/system.pa";
source = "${cfg.package}/etc/pulse/system.pa";
}
];
]);
# Allow PulseAudio to get realtime priority using rtkit.
security.rtkit.enable = true;
# Allow PulseAudio to get realtime priority using rtkit.
security.rtkit.enable = true;
};
})
];
}

View file

@ -0,0 +1,89 @@
Let all the files in the system tarball sit in a directory served by NFS (the
NFS root) like this in exportfs:
/home/pcroot 192.168.1.0/24(rw,no_root_squash,no_all_squash)
Run "exportfs -a" after editing /etc/exportfs, for the nfs server to be aware
of the changes.
Use a tftp server serving the root of boot/ (from the system tarball).
In order to have PXE boot, use the boot/dhcpd.conf-example file for your dhcpd
server, as it will point your PXE clients to pxelinux.0 from the tftp server.
Adapt the configuration to your network.
Adapt the pxelinux configuration (boot/pxelinux.cfg/default) to set the path to
your nfrroot. If you use ip=dhcp in the kernel, the nfs server ip will be taken
from dhcp and so you don't have to specify it.
The linux in bzImage includes network drivers for some usual cards.
QEMU Testing
---------------
You can test qemu pxe boot without having a DHCP server adapted, but having
nfsroot, like this:
qemu-system-x86_64 -tftp /home/pcroot/boot -net nic -net user,bootfile=pxelinux.0 -boot n
I don't know how to use NFS through the qemu '-net user' though.
QEMU Testing with NFS root and bridged network
-------------------------------------------------
This allows testing with qemu as any other host in your LAN.
Testing with the real dhcpd server requires setting up a bridge and having a
tap device.
tunctl -t tap0
brctl addbr br0
brctl addif br0 eth0
brctl addif tap0 eth0
ifconfig eth0 0.0.0.0 up
ifconfig tap0 0.0.0.0 up
ifconfig br0 up # With your ip configuration
Then you can run qemu:
qemu-system-x86_64 -boot n -net tap,ifname=tap0,script=no -net nic,model=e1000
Using the system-tarball-pc in a chroot
--------------------------------------------------
Installation:
mkdir nixos-chroot && cd nixos-chroot
tar xf your-system-tarball.tar.xz
mkdir sys dev proc tmp root var run
mount --bind /sys sys
mount --bind /dev dev
mount --bind /proc proc
Activate the system: look for a directory in nix/store similar to:
"/nix/store/y0d1lcj9fppli0hl3x0m0ba5g1ndjv2j-nixos-feb97bx-53f008"
Having found it, activate that nixos system *twice*:
chroot . /nix/store/SOMETHING-nixos-SOMETHING/activate
chroot . /nix/store/SOMETHING-nixos-SOMETHING/activate
This runs a 'hostname' command. Restore your old hostname with:
hostname OLDHOSTNAME
Copy your system resolv.conf to the /etc/resolv.conf inside the chroot:
cp /etc/resolv.conf etc
Then you can get an interactive shell in the nixos chroot. '*' means
to run inside the chroot interactive shell
chroot . /bin/sh
* source /etc/profile
Populate the nix database: that should be done in the init script if you
had booted this nixos. Run:
* `grep local-cmds run/current-system/init`
Then you can proceed normally subscribing to a nixos channel:
nix-channel --add http://nixos.org/releases/nixos/channels/nixos-unstable
nix-channel --update
Testing:
nix-env -i hello
which hello
hello

View file

@ -60,54 +60,7 @@ let
}
'';
readme = pkgs.writeText "readme.txt" ''
Let all the files in the system tarball sit in a directory served by NFS (the NFS root)
like this in exportfs:
/home/pcroot 192.168.1.0/24(rw,no_root_squash,no_all_squash)
Run "exportfs -a" after editing /etc/exportfs, for the nfs server to be aware of the
changes.
Use a tftp server serving the root of boot/ (from the system tarball).
In order to have PXE boot, use the boot/dhcpd.conf-example file for your dhcpd server,
as it will point your PXE clients to pxelinux.0 from the tftp server. Adapt the
configuration to your network.
Adapt the pxelinux configuration (boot/pxelinux.cfg/default) to set the path to your
nfrroot. If you use ip=dhcp in the kernel, the nfs server ip will be taken from
dhcp and so you don't have to specify it.
The linux in bzImage includes network drivers for some usual cards.
QEMU Testing
---------------
You can test qemu pxe boot without having a DHCP server adapted, but having nfsroot,
like this:
qemu-system-x86_64 -tftp /home/pcroot/boot -net nic -net user,bootfile=pxelinux.0 -boot n
I don't know how to use NFS through the qemu '-net user' though.
QEMU Testing with NFS root and bridged network
-------------------------------------------------
This allows testing with qemu as any other host in your LAN.
Testing with the real dhcpd server requires setting up a bridge and having a tap device.
tunctl -t tap0
brctl addbr br0
brctl addif br0 eth0
brctl addif tap0 eth0
ifconfig eth0 0.0.0.0 up
ifconfig tap0 0.0.0.0 up
ifconfig br0 up # With your ip configuration
Then you can run qemu:
qemu-system-x86_64 -boot n -net tap,ifname=tap0,script=no -net nic,model=e1000
'';
readme = ./system-tarball-pc-readme.txt;
in

View file

@ -6,6 +6,7 @@ let
crashdump = config.boot.crashDump;
kernelParams = concatStringsSep " " crashdump.kernelParams;
in
###### interface
{
@ -55,6 +56,8 @@ in
kernelParams = [
"crashkernel=64M"
"nmi_watchdog=panic"
"softlockup_panic=1"
"idle=poll"
];
kernelPackages = mkOverride 50 (crashdump.kernelPackages // {
kernel = crashdump.kernelPackages.kernel.override

View file

@ -74,6 +74,7 @@ in
bind = 53;
wwwrun = 54;
spamd = 56;
nslcd = 58;
# When adding a uid, make sure it doesn't match an existing gid.
@ -129,6 +130,7 @@ in
adm = 55;
spamd = 56;
networkmanager = 57;
nslcd = 58;
# When adding a gid, make sure it doesn't match an existing uid.

View file

@ -39,6 +39,7 @@
./programs/blcr.nix
./programs/info.nix
./programs/shadow.nix
./programs/shell.nix
./programs/ssh.nix
./programs/ssmtp.nix
./programs/wvdial.nix
@ -127,6 +128,7 @@
./services/networking/gnunet.nix
./services/networking/gogoclient.nix
./services/networking/gvpe.nix
./services/networking/hostapd.nix
./services/networking/ifplugd.nix
./services/networking/ircd-hybrid/default.nix
./services/networking/nat.nix

View file

@ -25,6 +25,10 @@ let
fi
'';
shellAliases = concatStringsSep "\n" (
mapAttrsFlatten (k: v: "alias ${k}='${v}'") config.environment.shellAliases
);
options = {
environment.promptInit = mkOption {
@ -90,12 +94,12 @@ in
{ # /etc/bashrc: executed every time a bash starts. Sources
# /etc/profile to ensure that the system environment is
# configured properly.
source = pkgs.substituteAll {
src = ./bashrc.sh;
inherit (config.environment) promptInit;
inherit initBashCompletion;
};
target = "bashrc";
source = pkgs.substituteAll {
src = ./bashrc.sh;
inherit (config.environment) promptInit;
inherit initBashCompletion shellAliases;
};
target = "bashrc";
}
{ # Configuration for readline in bash.
@ -104,6 +108,13 @@ in
}
];
environment.shellAliases =
{ ls = "ls --color=tty";
ll = "ls -l";
l = "ls -alh";
which = "type -P";
};
system.build.binsh = pkgs.bashInteractive;
system.activationScripts.binsh = stringAfter [ "stdio" ]

View file

@ -21,15 +21,4 @@ shopt -s checkwinsize
@promptInit@
@initBashCompletion@
# Some aliases.
alias ls="ls --color=tty"
alias ll="ls -l"
alias l="ls -alh"
alias which="type -P"
# Convenience for people used to Upstart.
alias start="systemctl start"
alias stop="systemctl stop"
alias restart="systemctl restart"
alias status="systemctl status"
@shellAliases@

View file

@ -0,0 +1,25 @@
# This module defines global configuration for the shells.
{ config, pkgs, ... }:
with pkgs.lib;
{
options = {
environment.shellAliases = mkOption {
type = types.attrs; # types.attrsOf types.stringOrPath;
default = {};
example = {
ll = "ls -lh";
};
description = ''
An attribute set that maps aliases (the top level attribute names in
this option) to command strings or directly to build outputs. The
aliases are added to all users' shells.
'';
};
};
config = {
};
}

View file

@ -16,11 +16,15 @@ in
programs.ssh = {
forwardX11 = mkOption {
default = cfgd.forwardX11;
default = false;
description = ''
Whether to request X11 forwarding on outgoing connections by default.
This is useful for running graphical programs on the remote machine and have them display to your local X11 server.
Historically, this value has depended on the value used by the local sshd daemon, but there really isn't a relation between the two.
Note: there are some security risks to forwarding an X11 connection.
NixOS's X server is built with the SECURITY extension, which prevents some obvious attacks.
To enable or disable forwarding on a per-connection basis, see the -X and -x options to ssh.
The -Y option to ssh enables trusted forwarding, which bypasses the SECURITY extension.
'';
};

View file

@ -7,7 +7,9 @@ with pkgs.lib;
let
inherit (pkgs) pam_ldap pam_krb5 pam_ccreds;
inherit (pkgs) pam_krb5 pam_ccreds;
pam_ldap = if config.users.ldap.daemon.enable then pkgs.nss_pam_ldapd else pkgs.pam_ldap;
otherService = pkgs.writeText "other.pam"
''
@ -249,6 +251,7 @@ in
{ name = "i3lock"; }
{ name = "lshd"; }
{ name = "samba"; }
{ name = "screen"; }
{ name = "vlock"; }
{ name = "xlock"; }
{ name = "xscreensaver"; }

View file

@ -5,16 +5,13 @@ 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/
'' );
defaultRules = pkgs.runCommand "logcheck-default-rules" {} ''
cp -prd ${pkgs.logcheck}/etc/logcheck $out
chmod u+w $out
rm $out/logcheck.*
'';
rulesDir = pkgs.symlinkJoin "logcheck-rules-dir" ([ defaultRules ] ++ cfg.extraRulesDirs);
configFile = pkgs.writeText "logcheck.conf" cfg.config;
@ -33,6 +30,74 @@ let
2 ${cfg.timeOfDay} * * * logcheck env PATH=/var/setuid-wrappers:$PATH nice -n10 ${pkgs.logcheck}/sbin/logcheck ${flags}
'';
writeIgnoreRule = name: {level, regex, ...}:
pkgs.writeTextFile
{ inherit name;
destination = "/ignore.d.${level}/${name}";
text = ''
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ ${regex}
'';
};
writeIgnoreCronRule = name: {level, user, regex, cmdline, ...}:
let escapeRegex = escape (stringToCharacters "\\[]{}()^$?*+|.");
cmdline_ = builtins.unsafeDiscardStringContext cmdline;
re = if regex != "" then regex else if cmdline_ == "" then ".*" else escapeRegex cmdline_;
in writeIgnoreRule "cron-${name}" {
inherit level;
regex = ''
(/usr/bin/)?cron\[[0-9]+\]: \(${user}\) CMD \(${re}\)$
'';
};
levelOption = mkOption {
default = "server";
type = types.uniq types.string;
description = ''
Set the logcheck level. Either "workstation", "server", or "paranoid".
'';
};
ignoreOptions = {
level = levelOption;
regex = mkOption {
default = "";
type = types.uniq types.string;
description = ''
Regex specifying which log lines to ignore.
'';
};
};
ignoreCronOptions = {
user = mkOption {
default = "root";
type = types.uniq types.string;
description = ''
User that runs the cronjob.
'';
};
cmdline = mkOption {
default = "";
type = types.uniq types.string;
description = ''
Command line for the cron job. Will be turned into a regex for the logcheck ignore rule.
'';
};
timeArgs = mkOption {
default = null;
type = types.nullOr (types.uniq types.string);
example = "02 06 * * *";
description = ''
"min hr dom mon dow" crontab time args, to auto-create a cronjob too.
Leave at null to not do this and just add a logcheck ignore rule.
'';
};
};
in
{
options = {
@ -98,16 +163,33 @@ in
'';
};
extraRulesDir = mkOption {
default = null;
extraRulesDirs = mkOption {
default = [];
example = "/etc/logcheck";
type = types.nullOr types.path;
type = types.listOf types.path;
description = ''
Directory with extra rules.
Will be merged with bundled rules, so it's possible to override certain behaviour.
Directories with extra rules.
'';
};
ignore = mkOption {
default = {};
description = ''
This option defines extra ignore rules.
'';
type = types.loaOf types.optionSet;
options = [ ignoreOptions ];
};
ignoreCron = mkOption {
default = {};
description = ''
This option defines extra ignore rules for cronjobs.
'';
type = types.loaOf types.optionSet;
options = [ ignoreOptions ignoreCronOptions ];
};
extraGroups = mkOption {
default = [];
type = types.listOf types.string;
@ -122,6 +204,10 @@ in
};
config = mkIf cfg.enable {
services.logcheck.extraRulesDirs =
mapAttrsToList writeIgnoreRule cfg.ignore
++ mapAttrsToList writeIgnoreCronRule cfg.ignoreCron;
users.extraUsers = singleton
{ name = cfg.user;
shell = "/bin/sh";
@ -134,6 +220,12 @@ in
chown ${cfg.user} /var/{lib,lock}/logcheck
'';
services.cron.systemCronJobs = [ cronJob ];
services.cron.systemCronJobs =
let withTime = name: {timeArgs, ...}: ! (builtins.isNull timeArgs);
mkCron = name: {user, cmdline, timeArgs, ...}: ''
${timeArgs} ${user} ${cmdline}
'';
in mapAttrsToList mkCron (filterAttrs withTime cfg.ignoreCron)
++ [ cronJob ];
};
}

View file

@ -24,7 +24,7 @@ let
smartdConf = pkgs.writeText "smartd.conf" (concatMapStrings (device:
''
${device} -a -m root -M exec ${smartdMail}
${device} -a -m root -M exec ${smartdMail} ${cfg.deviceOpts}
''
) cfg.devices);
@ -50,6 +50,17 @@ in
'';
};
deviceOpts = mkOption {
default = "";
type = types.string;
example = "-o on -s (S/../.././02|L/../../7/04)";
description = ''
Additional options for each device that is monitored. The example
turns on SMART Automatic Offline Testing on startup, and schedules short
self-tests daily, and long self-tests weekly.
'';
};
devices = mkOption {
default = [];
example = ["/dev/sda" "/dev/sdb"];

View file

@ -154,23 +154,23 @@ in
defaultShare = {
enable = mkOption {
description = "Whether to share /home/smbd as 'default'.";
default = false;
};
description = "Whether to share /home/smbd as 'default'.";
default = false;
};
writeable = mkOption {
description = "Whether to allow write access to default share.";
default = false;
};
description = "Whether to allow write access to default share.";
default = false;
};
guest = mkOption {
description = "Whether to allow guest access to default share.";
default = true;
};
description = "Whether to allow guest access to default share.";
default = true;
};
};
securityType = mkOption {
description = "Samba security type";
default = "user";
example = "share";
default = "user";
example = "share";
};
};
@ -180,43 +180,45 @@ in
###### implementation
config = mkIf config.services.samba.enable {
config = mkMerge
[ { # Always provide a smb.conf to shut up programs like smbclient and smbspool.
environment.etc = singleton
{ source =
if cfg.enable then configFile
else pkgs.writeText "smb-dummy.conf" "# Samba is disabled.";
target = "samba/smb.conf";
};
}
users.extraUsers = singleton
{ name = user;
description = "Samba service user";
group = group;
};
(mkIf config.services.samba.enable {
users.extraUsers = singleton
{ name = user;
description = "Samba service user";
group = group;
};
users.extraGroups = singleton
{ name = group;
};
users.extraGroups = singleton
{ name = group;
};
# always provide a smb.conf to shut up programs like smbclient and smbspool.
environment.etc = mkAlways (singleton
{ source =
if cfg.enable then configFile
else pkgs.writeText "smb-dummy.conf" "# Samba is disabled.";
target = "samba/smb.conf";
});
# Dummy job to start the real Samba daemons (nmbd, smbd, winbindd).
jobs.sambaControl =
{ name = "samba";
description = "Samba server";
# Dummy job to start the real Samba daemons (nmbd, smbd, winbindd).
jobs.sambaControl =
{ name = "samba";
description = "Samba server";
startOn = "started network-interfaces";
stopOn = "stopping network-interfaces";
startOn = "started network-interfaces";
stopOn = "stopping network-interfaces";
preStart = setupScript;
};
preStart = setupScript;
};
jobs.nmbd = daemonJob "nmbd" "-D";
jobs.nmbd = daemonJob "nmbd" "-D";
jobs.smbd = daemonJob "smbd" "-D";
jobs.smbd = daemonJob "smbd" "-D";
jobs.winbindd = daemonJob "winbindd" "-D";
};
jobs.winbindd = daemonJob "winbindd" "-D";
})
];
}

View file

@ -8,6 +8,10 @@ let
serversParam = concatMapStrings (s: "-S ${s} ") cfg.servers;
dnsmasqConf = pkgs.writeText "dnsmasq.conf" ''
${cfg.extraConfig}
'';
in
{
@ -33,6 +37,15 @@ in
'';
};
extraConfig = mkOption {
type = types.string;
default = "";
description = ''
Extra configuration directives that should be added to
<literal>dnsmasq.conf</literal>
'';
};
};
};
@ -49,7 +62,7 @@ in
daemonType = "daemon";
exec = "${dnsmasq}/bin/dnsmasq -R ${serversParam}";
exec = "${dnsmasq}/bin/dnsmasq -R ${serversParam} -o -C ${dnsmasqConf}";
};
};

View file

@ -39,6 +39,15 @@ let
}
'';
kernelPackages = config.boot.kernelPackages;
kernelHasRPFilter = kernelPackages.kernel ? features
&& kernelPackages.kernel.features ? netfilterRPFilter
&& kernelPackages.kernel.features.netfilterRPFilter;
kernelCanDisableHelpers = kernelPackages.kernel ? features
&& kernelPackages.kernel.features ? canDisableNetfilterConntrackHelpers
&& kernelPackages.kernel.features.canDisableNetfilterConntrackHelpers;
in
{
@ -140,6 +149,53 @@ in
'';
};
networking.firewall.checkReversePath = mkOption {
default = kernelHasRPFilter;
type = types.bool;
description =
''
Performs a reverse path filter test on a packet.
If a reply to the packet would not be sent via the same interface
that the packet arrived on, it is refused.
If using asymmetric routing or other complicated routing,
disable this setting and setup your own counter-measures.
(needs kernel 3.3+)
'';
};
networking.firewall.connectionTrackingModules = mkOption {
default = [ "ftp" ];
example = [ "ftp" "irc" "sane" "sip" "tftp" "amanda" "h323" "netbios_sn" "pptp" "snmp" ];
type = types.list types.string;
description =
''
List of connection-tracking helpers that are auto-loaded.
The complete list of possible values is given in the example.
As helpers can pose as a security risk, it is adviced to
set this to an empty list and disable the setting
networking.firewall.autoLoadConntrackHelpers
Loading of helpers is recommended to be done through the new
CT target. More info:
https://home.regit.org/netfilter-en/secure-use-of-helpers/
'';
};
networking.firewall.autoLoadConntrackHelpers = mkOption {
default = true;
type = types.bool;
description =
''
Whether to auto-load connection-tracking helpers.
See the description at networking.firewall.connectionTrackingModules
(needs kernel 3.5+)
'';
};
networking.firewall.extraCommands = mkOption {
default = "";
example = "iptables -A INPUT -p icmp -j ACCEPT";
@ -168,7 +224,16 @@ in
environment.systemPackages = [ pkgs.iptables ];
boot.kernelModules = [ "nf_conntrack_ftp" ];
boot.kernelModules = map (x: "nf_conntrack_${x}") cfg.connectionTrackingModules;
boot.extraModprobeConfig = optionalString (!cfg.autoLoadConntrackHelpers) ''
options nf_conntrack nf_conntrack_helper=0
'';
assertions = [ { assertion = ! cfg.checkReversePath || kernelHasRPFilter;
message = "This kernel does not support rpfilter"; }
{ assertion = cfg.autoLoadConntrackHelpers || kernelCanDisableHelpers;
message = "This kernel does not support disabling conntrack helpers"; }
];
jobs.firewall =
{ startOn = "started network-interfaces";
@ -232,6 +297,12 @@ in
# The "nixos-fw" chain does the actual work.
ip46tables -N nixos-fw
# Perform a reverse-path test to refuse spoofers
# For now, we just drop, as the raw table doesn't have a log-refuse yet
${optionalString (kernelHasRPFilter && cfg.checkReversePath) ''
ip46tables -A PREROUTING -t raw -m rpfilter --invert -j DROP
''}
# Accept all traffic on the trusted interfaces.
${flip concatMapStrings cfg.trustedInterfaces (iface: ''
ip46tables -A nixos-fw -i ${iface} -j nixos-fw-accept

View file

@ -0,0 +1,155 @@
{ config, pkgs, ... }:
# TODO:
#
# asserts
# ensure that the nl80211 module is loaded/compiled in the kernel
# hwMode must be a/b/g
# channel must be between 1 and 13 (maybe)
# wpa_supplicant and hostapd on the same wireless interface doesn't make any sense
# perhaps an assertion that there is a dhcp server and a dns server on the IP address serviced by the hostapd?
with pkgs.lib;
let
cfg = config.services.hostapd;
configFile = pkgs.writeText "hostapd.conf"
''
interface=${cfg.interface}
driver=${cfg.driver}
ssid=${cfg.ssid}
hw_mode=${cfg.hwMode}
channel=${toString cfg.channel}
# logging (debug level)
logger_syslog=-1
logger_syslog_level=2
logger_stdout=-1
logger_stdout_level=2
ctrl_interface=/var/run/hostapd
ctrl_interface_group=${cfg.group}
${if cfg.wpa then ''
wpa=1
wpa_passphrase=${cfg.wpaPassphrase}
'' else ""}
${cfg.extraCfg}
'' ;
in
{
###### interface
options = {
services.hostapd = {
enable = mkOption {
default = false;
description = ''
Enable putting a wireless interface into infrastructure mode,
allowing other wireless devices to associate with the wireless interface and do
wireless networking. A simple access point will enable hostapd.wpa, and
hostapd.wpa_passphrase, hostapd.ssid, dhcpd on the wireless interface to
provide IP addresses to the associated stations, and nat (from the wireless
interface to an upstream interface).
'';
};
interface = mkOption {
default = "";
example = "wlan0";
description = ''
The interfaces <command>hostapd</command> will use.
'';
};
driver = mkOption {
default = "nl80211";
example = "hostapd";
type = types.string;
description = "Which driver hostapd will use. Most things will probably use the default.";
};
ssid = mkOption {
default = "nixos";
example = "mySpecialSSID";
type = types.string;
description = "SSID to be used in IEEE 802.11 management frames.";
};
hwMode = mkOption {
default = "b";
example = "g";
type = types.string;
description = "Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g";
};
channel = mkOption {
default = 7;
example = 11;
type = types.int;
description =
''
Channel number (IEEE 802.11)
Please note that some drivers do not use this value from hostapd and the
channel will need to be configured separately with iwconfig.
'';
};
group = mkOption {
default = "wheel";
example = "network";
type = types.string;
description = "members of this group can control hostapd";
};
wpa = mkOption {
default = true;
description = "enable WPA (IEEE 802.11i/D3.0) to authenticate to the access point";
};
wpaPassphrase = mkOption {
default = "my_sekret";
example = "any_64_char_string";
type = types.string;
description =
''
WPA-PSK (pre-shared-key) passphrase. Clients will need this
passphrase to associate with this access point. Warning: This passphrase will
get put into a world-readable file in the nix store.
'';
};
extraCfg = mkOption {
default = "";
example = ''
auth_algo=0
ieee80211n=1
ht_capab=[HT40-][SHORT-GI-40][DSSS_CCK-40]
'';
type = types.string;
description = "Extra configuration options to put in the hostapd.conf";
};
};
};
###### implementation
config = mkIf cfg.enable {
environment.systemPackages = [ pkgs.hostapd ];
jobs.hostapd =
{ startOn = "started network-interfaces";
stopOn = "stopping network-interfaces";
exec = "${pkgs.hostapd}/bin/hostapd ${configFile}";
};
};
}

View file

@ -1,4 +1,6 @@
# This module enables Network Address Translation (NAT).
# XXX: todo: support multiple upstream links
# see http://yesican.chsoft.biz/lartc/MultihomedLinuxNetworking.html
{ config, pkgs, ... }:
@ -25,13 +27,16 @@ in
};
networking.nat.internalIPs = mkOption {
example = "192.168.1.0/24";
example = [ "192.168.1.0/24" ] ;
description =
''
The IP address range for which to perform NAT. Packets
coming from these addresses and destined for the external
The IP address ranges for which to perform NAT. Packets
coming from these networks and destined for the external
interface will be rewritten.
'';
# Backward compatibility: this used to be a single range instead
# of a list.
apply = x: if isList x then x else [x];
};
networking.nat.externalInterface = mkOption {
@ -76,13 +81,17 @@ in
''
iptables -t nat -F POSTROUTING
iptables -t nat -X
''
+ (concatMapStrings (network:
''
iptables -t nat -A POSTROUTING \
-s ${cfg.internalIPs} -o ${cfg.externalInterface} \
-s ${network} -o ${cfg.externalInterface} \
${if cfg.externalIP == ""
then "-j MASQUERADE"
else "-j SNAT --to-source ${cfg.externalIP}"}
''
) cfg.internalIPs) +
''
echo 1 > /proc/sys/net/ipv4/ip_forward
'';
@ -91,7 +100,5 @@ in
iptables -t nat -F POSTROUTING
'';
};
};
}

View file

@ -41,7 +41,7 @@ in
flags = "REUSE NAMEINARGS";
protocol = "tcp";
user = "root";
server = "${pkgs.tcpWrapper}/sbin/tcpd";
server = "${pkgs.tcp_wrappers}/sbin/tcpd";
serverArgs = "${pkgs.heimdal}/sbin/kadmind";
};

View file

@ -8,6 +8,8 @@ let
httpd = mainCfg.package;
version24 = !versionOlder httpd.version "2.4";
httpdConf = mainCfg.configFile;
php = pkgs.php.override { apacheHttpd = httpd; };
@ -101,7 +103,8 @@ let
"auth_basic" "auth_digest"
# Authentication: is the user who he claims to be?
"authn_file" "authn_dbm" "authn_anon" "authn_alias"
"authn_file" "authn_dbm" "authn_anon"
(if version24 then "authn_core" else "authn_alias")
# Authorization: is the user allowed access?
"authz_user" "authz_groupfile" "authz_host"
@ -113,11 +116,31 @@ let
"vhost_alias" "negotiation" "dir" "imagemap" "actions" "speling"
"userdir" "alias" "rewrite" "proxy" "proxy_http"
]
++ optionals version24 [
"mpm_${mainCfg.multiProcessingModule}"
"authz_core"
"unixd"
]
++ (if mainCfg.multiProcessingModule == "prefork" then [ "cgi" ] else [ "cgid" ])
++ optional enableSSL "ssl"
++ extraApacheModules;
allDenied = if version24 then ''
Require all denied
'' else ''
Order deny,allow
Deny from all
'';
allGranted = if version24 then ''
Require all granted
'' else ''
Order allow,deny
Allow from all
'';
loggingConf = ''
ErrorLog ${mainCfg.logDir}/error_log
@ -186,8 +209,7 @@ let
<Directory "${documentRoot}">
Options Indexes FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
${allGranted}
</Directory>
'';
@ -241,12 +263,10 @@ let
AllowOverride FileInfo AuthConfig Limit Indexes
Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
<Limit GET POST OPTIONS>
Order allow,deny
Allow from all
${allGranted}
</Limit>
<LimitExcept GET POST OPTIONS>
Order deny,allow
Deny from all
${allDenied}
</LimitExcept>
</Directory>
@ -268,8 +288,7 @@ let
Alias ${elem.urlPath} ${elem.dir}/
<Directory ${elem.dir}>
Options +Indexes
Order allow,deny
Allow from all
${allGranted}
AllowOverride All
</Directory>
'';
@ -286,6 +305,10 @@ let
ServerRoot ${httpd}
${optionalString version24 ''
DefaultRuntimeDir ${mainCfg.stateDir}/runtime
''}
PidFile ${mainCfg.stateDir}/httpd.pid
${optionalString (mainCfg.multiProcessingModule != "prefork") ''
@ -321,8 +344,7 @@ let
AddHandler type-map var
<Files ~ "^\.ht">
Order allow,deny
Deny from all
${allDenied}
</Files>
${mimeConf}
@ -340,16 +362,14 @@ let
<Directory />
Options FollowSymLinks
AllowOverride None
Order deny,allow
Deny from all
${allDenied}
</Directory>
# But do allow access to files in the store so that we don't have
# to generate <Directory> clauses for every generated file that we
# want to serve.
<Directory /nix/store>
Order allow,deny
Allow from all
${allGranted}
</Directory>
# Generate directives for the main server.
@ -359,7 +379,8 @@ let
${let
ports = map getPort allHosts;
uniquePorts = uniqList {inputList = ports;};
in concatMapStrings (port: "NameVirtualHost *:${toString port}\n") uniquePorts
directives = concatMapStrings (port: "NameVirtualHost *:${toString port}\n") uniquePorts;
in optionalString (!version24) directives
}
${let
@ -604,6 +625,10 @@ in
''
mkdir -m 0750 -p ${mainCfg.stateDir}
chown root.${mainCfg.group} ${mainCfg.stateDir}
${optionalString version24 ''
mkdir -m 0750 -p "${mainCfg.stateDir}/runtime"
chown root.${mainCfg.group} "${mainCfg.stateDir}/runtime"
''}
mkdir -m 0700 -p ${mainCfg.logDir}
${optionalString (mainCfg.documentRoot != null)

View file

@ -343,7 +343,8 @@ in
optional (elem "virtualbox" driverNames) kernelPackages.virtualboxGuestAdditions ++
optional (elem "ati_unfree" driverNames) kernelPackages.ati_drivers_x11;
environment.etc = optionals cfg.exportConfiguration
environment.etc =
(optionals cfg.exportConfiguration
[ { source = "${configFile}";
target = "X11/xorg.conf";
}
@ -351,7 +352,15 @@ in
{ source = "${pkgs.xkeyboard_config}/etc/X11/xkb";
target = "X11/xkb";
}
];
])
++ (optionals (elem "ati_unfree" driverNames) [
# according toiive on #ati you don't need the pcs, it is like registry... keeps old stuff to make your
# life harder ;) Still it seems to be required
{ source = "${kernelPackages.ati_drivers_x11}/etc/ati";
target = "ati";
}
]);
environment.x11Packages =
[ xorg.xorgserver
@ -417,6 +426,8 @@ in
"ln -sf ${kernelPackages.nvidia_x11_legacy96} /run/opengl-driver"
else if elem "nvidiaLegacy173" driverNames then
"ln -sf ${kernelPackages.nvidia_x11_legacy173} /run/opengl-driver"
else if elem "ati_unfree" driverNames then
"ln -sf ${kernelPackages.ati_drivers_x11} /run/opengl-driver"
else if cfg.driSupport then
"ln -sf ${pkgs.mesa} /run/opengl-driver"
else ""

View file

@ -40,10 +40,10 @@ EOF
case $reply in
f)
exec setsid @shell@ < /dev/$console >/dev/$console 2>/dev/$console ;;
exec setsid @shell@ -c "@shell@ < /dev/$console >/dev/$console 2>/dev/$console" ;;
i)
echo "Starting interactive shell..."
setsid @shell@ < /dev/$console >/dev/$console 2>/dev/$console || fail
setsid @shell@ -c "@shell@ < /dev/$console >/dev/$console 2>/dev/$console" || fail
;;
*)
echo "Continuing...";;

View file

@ -469,5 +469,12 @@ in
"CGROUPS" "AUTOFS4_FS" "DEVTMPFS"
];
environment.shellAliases =
{ start = "systemctl start";
stop = "systemctl stop";
restart = "systemctl restart";
status = "systemctl status";
};
};
}

View file

@ -5,8 +5,19 @@
{ config, pkgs, ... }:
with pkgs.lib;
let
options = {
ec2.metadata = mkOption {
type = types.bool;
default = false;
description = ''
Whether to allow access to EC2 metadata.
'';
};
};
in
{
require = [options];
boot.systemd.services."fetch-ec2-data" =
{ description = "Fetch EC2 Data";
@ -56,9 +67,11 @@ with pkgs.lib;
echo "$key_pub" > /etc/ssh/ssh_host_dsa_key.pub
fi
${optionalString (! config.ec2.metadata) ''
# Since the user data is sensitive, prevent it from being
# accessed from now on.
ip route add blackhole 169.254.169.254/32
''}
'';
serviceConfig.Type = "oneshot";