summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortv <tv@shackspace.de>2015-03-05 13:01:05 +0100
committertv <tv@shackspace.de>2015-05-19 23:10:57 +0200
commitf93ca99fab906b6d2b83dc3b4c9410da7c29bdde (patch)
treee34e330c04beb0822d59da3f43b0a1e32c06b582
initial commit
-rw-r--r--certs/zalora-ca.crt24
-rw-r--r--lib/default.nix44
-rw-r--r--modules/base.nix17
-rw-r--r--modules/exim.nix122
-rw-r--r--modules/hosts.nix25
-rw-r--r--modules/iptables.nix69
-rw-r--r--modules/nginx.nix30
-rw-r--r--modules/retiolum.nix224
-rw-r--r--modules/tools.nix101
-rw-r--r--modules/urxvt.nix24
-rw-r--r--modules/users.nix226
-rw-r--r--modules/xserver.nix51
-rw-r--r--wu.nix457
13 files changed, 1414 insertions, 0 deletions
diff --git a/certs/zalora-ca.crt b/certs/zalora-ca.crt
new file mode 100644
index 000000000..12cdf8fc6
--- /dev/null
+++ b/certs/zalora-ca.crt
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIID7zCCAtegAwIBAgIJAPImpJwMgGmhMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYD
+VQQGEwJTRzESMBAGA1UECAwJU2luZ2Fwb3JlMQ8wDQYDVQQKDAZaYWxvcmExCzAJ
+BgNVBAsMAklUMSUwIwYDVQQDDBxaYWxvcmEgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
+MSUwIwYJKoZIhvcNAQkBFhZpdC1zZXJ2aWNlc0B6YWxvcmEuY29tMB4XDTE0MDkx
+ODIxNDY0N1oXDTI0MDkxNTIxNDY0N1owgY0xCzAJBgNVBAYTAlNHMRIwEAYDVQQI
+DAlTaW5nYXBvcmUxDzANBgNVBAoMBlphbG9yYTELMAkGA1UECwwCSVQxJTAjBgNV
+BAMMHFphbG9yYSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxJTAjBgkqhkiG9w0BCQEW
+Fml0LXNlcnZpY2VzQHphbG9yYS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDi48Tkh6XuS2gdE1+gsPPQjTI8Q2wbXqZGTHnyAZx75btOIUZHeHJm
+Fvu8erAD+vtx1nD1GOG30uvHFk9Of2mFY1fxw0R1LthJHSLFJU1/GjFSggHWkaI3
+HBSmeALjss/XHG3EtShLo8SHBc/+B8ehqj1JqcXF8q50JtfTQ+zlf+k26ke2S5Xo
+OdHLxjlNaPwj+TgJI1DHqs/bTapaPHPKk5+jFQzAcMmq0bygzpQTHCvvKqcoXaJk
+UgDBQnVsJUtwfObrM1TKu2TOXUhqgfnnflYf2sz5Sr30QlkrHP+PM3BRLB+6FXhr
+UlKKVcAcIwrBo0aJ5Sd0fv39GwV1XCWVAgMBAAGjUDBOMB0GA1UdDgQWBBQFftMH
+5/dc0pUNDqLbVQ8gm7+I5TAfBgNVHSMEGDAWgBQFftMH5/dc0pUNDqLbVQ8gm7+I
+5TAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQC2aSKJ15v5OI7Zj/HQ
+lW+iY9STBPJi9lgOjaGrNaPX0IuhJLkeKDntmzjvpGwvcylHMp6Im02svTymteNN
+38s8A0aStnmW4ysGT853H7L7Jxzf7J2vrUF0Dj4QkZ07Gp3vAgKnWVcqz36Xr0Se
+DEqrKMl/6fq3Ygl35fZXP1kb6t/wP6qx69bnENH6ksHFpZapWYssKNZO9yiB8+Eq
+ngB22X/ycMmAqOnNQDzw1JBw7LzdXypCG75UKEK6kbnUy2yPADdHpH8v9qcRa1U9
+vEmUTJs6i1CpPO+2frPJ8A8QIp61nNxe7xJ1SnNVtwk9d6SRet6YGySvgG748Wjw
+GwWx
+-----END CERTIFICATE-----
diff --git a/lib/default.nix b/lib/default.nix
new file mode 100644
index 000000000..c1663a7b8
--- /dev/null
+++ b/lib/default.nix
@@ -0,0 +1,44 @@
+{ pkgs, ... }:
+
+with builtins;
+
+let
+ inherit (pkgs.lib) stringAsChars;
+in
+
+{
+
+
+ # "7.4.335" -> "74"
+ majmin = with pkgs.lib; x : concatStrings (take 2 (splitString "." x));
+
+
+ concat = xs :
+ if xs == []
+ then ""
+ else head xs + concat (tail xs)
+ ;
+
+ flip = f : x : y : f y x;
+
+ # isSuffixOf :: String -> String -> Bool
+ isSuffixOf =
+ s : xs :
+ let
+ sn = stringLength s;
+ xsn = stringLength xs;
+ in
+ xsn >= sn && substring (xsn - sn) sn xs == s ;
+
+ removeSuffix =
+ s : xs : substring 0 (stringLength xs - stringLength s) xs;
+
+ # setMap :: (String -> a -> b) -> Set String a -> [b]
+ #setMap = f: xs: map (k : f k (getAttr k xs)) (attrNames xs);
+
+ # setToList :: Set k a -> [a]
+ #setToList = setMap (_: v: v);
+
+ shell-escape =
+ stringAsChars (c: if c == "\n" then ''"${c}"'' else "\\${c}");
+}
diff --git a/modules/base.nix b/modules/base.nix
new file mode 100644
index 000000000..76c8b8970
--- /dev/null
+++ b/modules/base.nix
@@ -0,0 +1,17 @@
+{ config, pkgs, ... }:
+
+{
+ time.timeZone = "Europe/Berlin";
+
+ nix.maxJobs = 8;
+ nix.useChroot = true;
+ # TODO check if both are required:
+ nix.chrootDirs = [ "/etc/protocols" pkgs.iana_etc.outPath ];
+
+ nix.trustedBinaryCaches = [
+ "https://cache.nixos.org"
+ "http://cache.nixos.org"
+ "http://hydra.nixos.org"
+ ];
+
+}
diff --git a/modules/exim.nix b/modules/exim.nix
new file mode 100644
index 000000000..4a0232c8c
--- /dev/null
+++ b/modules/exim.nix
@@ -0,0 +1,122 @@
+{ config, pkgs, ... }:
+
+{
+ services.exim =
+ let
+ retiolumHostname = "wu.retiolum"; # TODO "${networking.hostName}.retiolum";
+ in
+ { enable = true;
+ config = ''
+ primary_hostname = ${retiolumHostname}
+ domainlist local_domains = @ : localhost
+ domainlist relay_to_domains = *.retiolum
+ hostlist relay_from_hosts = <; 127.0.0.1 ; ::1
+
+ acl_smtp_rcpt = acl_check_rcpt
+ acl_smtp_data = acl_check_data
+
+ host_lookup = *
+ rfc1413_hosts = *
+ rfc1413_query_timeout = 5s
+
+ log_file_path = syslog
+ syslog_timestamp = false
+ syslog_duplication = false
+
+ begin acl
+
+ acl_check_rcpt:
+ accept hosts = :
+ control = dkim_disable_verify
+
+ deny message = Restricted characters in address
+ domains = +local_domains
+ local_parts = ^[.] : ^.*[@%!/|]
+
+ deny message = Restricted characters in address
+ domains = !+local_domains
+ local_parts = ^[./|] : ^.*[@%!] : ^.*/\\.\\./
+
+ accept local_parts = postmaster
+ domains = +local_domains
+
+ #accept
+ # hosts = *.retiolum
+ # domains = *.retiolum
+ # control = dkim_disable_verify
+
+ #require verify = sender
+
+ accept hosts = +relay_from_hosts
+ control = submission
+ control = dkim_disable_verify
+
+ accept authenticated = *
+ control = submission
+ control = dkim_disable_verify
+
+ require message = relay not permitted
+ domains = +local_domains : +relay_to_domains
+
+ require verify = recipient
+
+ accept
+
+
+ acl_check_data:
+ accept
+
+
+ begin routers
+
+ retiolum:
+ driver = manualroute
+ domains = ! ${retiolumHostname} : *.retiolum
+ transport = remote_smtp
+ route_list = ^.* $0 byname
+ no_more
+
+ nonlocal:
+ debug_print = "R: nonlocal for $local_part@$domain"
+ driver = redirect
+ domains = ! +local_domains
+ allow_fail
+ data = :fail: Mailing to remote domains not supported
+ no_more
+
+ local_user:
+ # debug_print = "R: local_user for $local_part@$domain"
+ driver = accept
+ check_local_user
+ # local_part_suffix = +* : -*
+ # local_part_suffix_optional
+ transport = home_maildir
+ cannot_route_message = Unknown user
+
+
+ begin transports
+
+ remote_smtp:
+ driver = smtp
+
+ home_maildir:
+ driver = appendfile
+ maildir_format
+ directory = $home/Maildir
+ directory_mode = 0700
+ delivery_date_add
+ envelope_to_add
+ return_path_add
+ # group = mail
+ # mode = 0660
+
+ begin retry
+ *.retiolum * F,42d,1m
+ * * F,2h,15m; G,16h,1h,1.5; F,4d,6h
+
+ begin rewrite
+
+ begin authenticators
+ '';
+ };
+}
diff --git a/modules/hosts.nix b/modules/hosts.nix
new file mode 100644
index 000000000..f59f87cc0
--- /dev/null
+++ b/modules/hosts.nix
@@ -0,0 +1,25 @@
+{ config, pkgs, ... }:
+
+{
+ networking.extraHosts =
+ ''
+ 192.168.1.1 wrt.gg23 wrt
+ 192.168.1.11 mors.gg23
+ 192.168.1.12 uriel.gg23
+ 192.168.1.23 raspi.gg23 raspi
+ 192.168.1.37 wu.gg23
+ 192.168.1.110 nomic.gg23
+ 192.168.1.124 schnabeldrucker.gg23 schnabeldrucker
+
+ 127.0.0.1 dev.zalora.sg www.dev.zalora.sg bob.dev.zalora.sg static.dev.zalora.sg
+ 127.0.0.1 dev.zalora.com.my www.dev.zalora.com.my bob.dev.zalora.com.my static.dev.zalora.com.my
+ 127.0.0.1 dev.zalora.com.ph www.dev.zalora.com.ph bob.dev.zalora.com.ph static.dev.zalora.com.ph
+ 127.0.0.1 dev.zalora.vn www.dev.zalora.vn bob.dev.zalora.vn static.dev.zalora.vn
+ 127.0.0.1 dev.zalora.co.id www.dev.zalora.co.id bob.dev.zalora.co.id static.dev.zalora.co.id
+ 127.0.0.1 dev.zalora.co.th www.dev.zalora.co.th bob.dev.zalora.co.th static.dev.zalora.co.th
+ 127.0.0.1 dev.zalora.com.hk www.dev.zalora.com.hk bob.dev.zalora.com.hk static.dev.zalora.com.hk
+
+ 54.93.104.95 eu-dev.hk.zalora.net www.eu-dev.hk.zalora.net bob.eu-dev.hk.zalora.net static.eu-dev.hk.zalora.net
+ 54.93.104.95 eu-dev.sg.zalora.net www.eu-dev.sg.zalora.net bob.eu-dev.sg.zalora.net static.eu-dev.sg.zalora.net
+ '';
+}
diff --git a/modules/iptables.nix b/modules/iptables.nix
new file mode 100644
index 000000000..ee4034321
--- /dev/null
+++ b/modules/iptables.nix
@@ -0,0 +1,69 @@
+{ config, pkgs, ... }:
+
+{
+ #
+ # iptables
+ #
+ networking.firewall.enable = false;
+ system.activationScripts.iptables =
+ let
+ log = false;
+ when = c: f: if c then f else "";
+ in
+ ''
+ ip4tables() { ${pkgs.iptables}/sbin/iptables "$@"; }
+ ip6tables() { ${pkgs.iptables}/sbin/ip6tables "$@"; }
+ ipXtables() { ip4tables "$@"; ip6tables "$@"; }
+
+ #
+ # nat
+ #
+
+ # reset tables
+ ipXtables -t nat -F
+ ipXtables -t nat -X
+
+ #
+ ipXtables -t nat -A PREROUTING -j REDIRECT ! -i retiolum -p tcp --dport ssh --to-ports 0
+ ipXtables -t nat -A PREROUTING -j REDIRECT -p tcp --dport 11423 --to-ports ssh
+
+ #
+ # filter
+ #
+
+ # reset tables
+ ipXtables -P INPUT DROP
+ ipXtables -P FORWARD DROP
+ ipXtables -F
+ ipXtables -X
+
+ # create custom chains
+ ipXtables -N Retiolum
+
+ # INPUT
+ ipXtables -A INPUT -j ACCEPT -m conntrack --ctstate RELATED,ESTABLISHED
+ ipXtables -A INPUT -j ACCEPT -i lo
+ ipXtables -A INPUT -j ACCEPT -p tcp --dport ssh -m conntrack --ctstate NEW
+ ipXtables -A INPUT -j ACCEPT -p tcp --dport http -m conntrack --ctstate NEW
+ ipXtables -A INPUT -j ACCEPT -p tcp --dport tinc -m conntrack --ctstate NEW
+ ipXtables -A INPUT -j ACCEPT -p tcp --dport smtp -m conntrack --ctstate NEW
+ ipXtables -A INPUT -j Retiolum -i retiolum
+ ${when log "ipXtables -A INPUT -j LOG --log-level info --log-prefix 'INPUT DROP '"}
+
+ # FORWARD
+ ${when log "ipXtables -A FORWARD -j LOG --log-level info --log-prefix 'FORWARD DROP '"}
+
+ # Retiolum
+ ip4tables -A Retiolum -j ACCEPT -p icmp --icmp-type echo-request
+ ip6tables -A Retiolum -j ACCEPT -p ipv6-icmp -m icmp6 --icmpv6-type echo-request
+
+
+ ${when log "ipXtables -A Retiolum -j LOG --log-level info --log-prefix 'REJECT '"}
+ ipXtables -A Retiolum -j REJECT -p tcp --reject-with tcp-reset
+ ip4tables -A Retiolum -j REJECT -p udp --reject-with icmp-port-unreachable
+ ip4tables -A Retiolum -j REJECT --reject-with icmp-proto-unreachable
+ ip6tables -A Retiolum -j REJECT -p udp --reject-with icmp6-port-unreachable
+ ip6tables -A Retiolum -j REJECT
+
+ '';
+}
diff --git a/modules/nginx.nix b/modules/nginx.nix
new file mode 100644
index 000000000..8b420613b
--- /dev/null
+++ b/modules/nginx.nix
@@ -0,0 +1,30 @@
+{ config, pkgs, ... }:
+
+{
+ services.nginx =
+ let
+ name = config.networking.hostName;
+ qname = "${name}.retiolum";
+ in
+ {
+ enable = true;
+ httpConfig = ''
+ sendfile on;
+ server {
+ listen 80;
+ server_name ${name} ${qname} localhost;
+ root /srv/http/${name};
+ location ~ ^/~(.+?)(/.*)?$ {
+ alias /home/$1/public_html$2;
+ }
+ }
+ types {
+ text/css css;
+ text/html html;
+ image/svg+xml svg;
+ }
+ default_type text/html;
+ charset utf-8;
+ '';
+ };
+}
diff --git a/modules/retiolum.nix b/modules/retiolum.nix
new file mode 100644
index 000000000..40112165b
--- /dev/null
+++ b/modules/retiolum.nix
@@ -0,0 +1,224 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+
+ ###### interface
+
+ options = {
+ services.retiolum = {
+
+ enable = mkOption {
+ type = types.bool;
+ default = false;
+ description = "Enable tinc daemon for Retiolum.";
+ };
+
+ name = mkOption {
+ type = types.string;
+ default = config.networking.hostName;
+ # Description stolen from tinc.conf(5).
+ description = ''
+ This is the name which identifies this tinc daemon. It must
+ be unique for the virtual private network this daemon will
+ connect to. The Name may only consist of alphanumeric and
+ underscore characters. If Name starts with a $, then the
+ contents of the environment variable that follows will be
+ used. In that case, invalid characters will be converted to
+ underscores. If Name is $HOST, but no such environment
+ variable exist, the hostname will be read using the
+ gethostnname() system call This is the name which identifies
+ the this tinc daemon.
+ '';
+ };
+
+ generateEtcHosts = mkOption {
+ type = types.string;
+ default = "both";
+ description = ''
+ If set to <literal>short</literal>, <literal>long</literal>, or <literal>both</literal>,
+ then generate entries in <filename>/etc/hosts</filename> from subnets.
+ '';
+ };
+
+ network = mkOption {
+ type = types.string;
+ default = "retiolum";
+ description = ''
+ The tinc network name.
+ It is used to generate long host entries,
+ derive the name of the user account under which tincd runs,
+ and name the TUN device.
+ '';
+ };
+
+ tincPackage = mkOption {
+ type = types.package;
+ default = pkgs.tinc;
+ description = "Tincd package to use.";
+ };
+
+ hosts = mkOption {
+ default = null;
+ description = ''
+ Hosts package or path to use.
+ If a path is given, then it will be used to generate an ad-hoc package.
+ '';
+ };
+
+ iproutePackage = mkOption {
+ type = types.package;
+ default = pkgs.iproute;
+ description = "Iproute2 package to use.";
+ };
+
+
+ privateKeyFile = mkOption {
+ # TODO if it's types.path then it gets copied to /nix/store with
+ # bad unsafe permissions...
+ type = types.string;
+ default = "/etc/tinc/retiolum/rsa_key.priv";
+ description = "Generate file with <literal>tincd -K</literal>.";
+ };
+
+ connectTo = mkOption {
+ type = types.listOf types.string;
+ default = [ "fastpoke" "pigstarter" "kheurop" ];
+ description = "TODO describe me";
+ };
+
+ };
+ };
+
+
+ ###### implementation
+
+ config =
+ let
+ cfg = config.services.retiolum;
+ tinc = cfg.tincPackage;
+ hostsType = builtins.typeOf cfg.hosts;
+ hosts =
+ if hostsType == "package" then
+ # use package as is
+ cfg.hosts
+ else if hostsType == "path" then
+ # use path to generate a package
+ pkgs.stdenv.mkDerivation {
+ name = "custom-retiolum-hosts";
+ src = cfg.hosts;
+ installPhase = ''
+ mkdir $out
+ find . -name .git -prune -o -type f -print0 | xargs -0 cp --target-directory $out
+ '';
+ }
+ else
+ abort "The option `services.retiolum.hosts' must be set to a package or a path"
+ ;
+ iproute = cfg.iproutePackage;
+
+ retiolumExtraHosts = import (pkgs.runCommand "retiolum-etc-hosts"
+ { }
+ ''
+ generate() {
+ (cd ${hosts}
+ printf \'\'
+ for i in `ls`; do
+ sed -En '
+ s|^ *Subnet *= *([^ /]*)(/[0-9]*)? *$|\1 '"$(hostnames $i)"'|p
+ ' $i
+ done | sort
+ printf \'\'
+ )
+ }
+
+ case ${cfg.generateEtcHosts} in
+ short)
+ hostnames() { echo "$1"; }
+ generate
+ ;;
+ long)
+ hostnames() { echo "$1.${cfg.network}"; }
+ generate
+ ;;
+ both)
+ hostnames() { echo "$1.${cfg.network} $1"; }
+ generate
+ ;;
+ *)
+ echo '""'
+ ;;
+ esac > $out
+ '');
+
+
+ confDir = pkgs.runCommand "retiolum" {
+ # TODO text
+ executable = true;
+ preferLocalBuild = true;
+ } ''
+ set -euf
+
+ mkdir -p $out
+
+ ln -s ${hosts} $out/hosts
+
+ cat > $out/tinc.conf <<EOF
+ Name = ${cfg.name}
+ Device = /dev/net/tun
+ Interface = ${cfg.network}
+ ${concatStrings (map (c : "ConnectTo = " + c + "\n") cfg.connectTo)}
+ PrivateKeyFile = ${cfg.privateKeyFile}
+ EOF
+
+ # source: krebscode/painload/retiolum/scripts/tinc_setup/tinc-up
+ cat > $out/tinc-up <<EOF
+ host=$out/hosts/${cfg.name}
+ ${iproute}/sbin/ip link set \$INTERFACE up
+
+ addr4=\$(sed -n 's|^ *Subnet *= *\(10[.][^ ]*\) *$|\1|p' \$host)
+ if [ -n "\$addr4" ];then
+ ${iproute}/sbin/ip -4 addr add \$addr4 dev \$INTERFACE
+ ${iproute}/sbin/ip -4 route add 10.243.0.0/16 dev \$INTERFACE
+ fi
+ addr6=\$(sed -n 's|^ *Subnet *= *\(42[:][^ ]*\) *$|\1|p' \$host)
+ ${iproute}/sbin/ip -6 addr add \$addr6 dev \$INTERFACE
+ ${iproute}/sbin/ip -6 route add 42::/16 dev \$INTERFACE
+ EOF
+
+ chmod +x $out/tinc-up
+ '';
+
+
+ user = cfg.network + "-tinc";
+
+ in
+
+ mkIf cfg.enable {
+ environment.systemPackages = [ tinc hosts iproute ];
+
+ networking.extraHosts = retiolumExtraHosts;
+
+ systemd.services.retiolum = {
+ description = "Tinc daemon for Retiolum";
+ after = [ "network.target" ];
+ wantedBy = [ "multi-user.target" ];
+ path = [ tinc iproute ];
+ serviceConfig = {
+ # TODO we cannot chroot (-R) b/c we use symlinks to hosts
+ # and the private key.
+ ExecStart = "${tinc}/sbin/tincd -c ${confDir} -d 0 -U ${user} -D";
+ SyslogIdentifier = "retiolum-tincd";
+ };
+ restartIfChanged = true;
+ };
+
+ users.extraUsers = singleton {
+ name = user;
+ uid = 42; # TODO config.ids.uids.retiolum
+ };
+
+ };
+
+}
diff --git a/modules/tools.nix b/modules/tools.nix
new file mode 100644
index 000000000..4be84a6be
--- /dev/null
+++ b/modules/tools.nix
@@ -0,0 +1,101 @@
+{ config, pkgs, ... }:
+
+let
+ inherit (pkgs) lib stdenv;
+ inherit (lib.strings) concatStringsSep stringAsChars;
+ inherit (lib.attrsets) attrValues mapAttrs;
+ inherit (lib) makeSearchPath;
+ inherit (import ../lib { inherit pkgs; }) shell-escape;
+
+
+ # TODO make these scripts available in an maintenance shell
+
+
+ scripts = {
+
+ # just so we don't reboot accidentally
+ reboot =
+ ''
+ echo no reboot >&2
+ exit 23
+ '';
+
+ rebuild =
+ ''
+ nixpkgs=''${nixpkgs-/home/tv/src/nixpkgs}
+ nixos-rebuild \
+ --show-trace \
+ -I nixpkgs="$nixpkgs" \
+ switch \
+ 2>&1 \
+ | sed ${shell-escape ''
+ s|"\(/home/tv/src/config/[^":]*\)"|\1|
+ s|^trace:\s*\(.*\)|\1|
+ ''}
+ '';
+
+ };
+
+ wrap = script:
+ ''
+ #! /bin/sh
+ set -euf
+ ${script}
+ '';
+ #lib=$lib
+ #export PATH=$bin:${makeSearchPath "bin" buildInputs}
+
+ buildScript = name: script:
+ builtins.trace "building ${name}"
+ ''
+ echo ${shell-escape script} > $bin/${shell-escape name}
+ chmod +x $bin/${shell-escape name}
+ '';
+
+
+
+ tools = pkgs.stdenv.mkDerivation rec {
+ name = "tools";
+ src = /var/empty;
+
+ buildInputs = [];
+
+
+ buildPhase =
+ ''
+ mkdir $out
+
+ bin=$out/bin
+ mkdir $bin
+
+ ${concatStringsSep "\n" (attrValues (mapAttrs buildScript scripts))}
+
+ '';
+ #''
+ #mkdir $out
+
+ #lib=$out/lib
+ #cp -r lib $lib
+
+ #bin=$out/bin
+ #mkdir $bin
+ #${concatStringsSep "\n" (attrValues (mapAttrs (name: script:
+ # ''
+ # {
+ # echo '#! /bin/sh'
+ # echo 'set -euf'
+ # echo "lib=$lib"
+ # echo "export PATH=$bin:${makeSearchPath "bin" buildInputs}"
+ # echo ${shell-escape script}
+ # } > $bin/${name}
+ # chmod +x $bin/${name}
+ # '') scripts))}
+ #'';
+ installPhase = ":";
+ };
+
+in
+
+{
+ environment.systemPackages = [ tools ];
+}
diff --git a/modules/urxvt.nix b/modules/urxvt.nix
new file mode 100644
index 000000000..a97581248
--- /dev/null
+++ b/modules/urxvt.nix
@@ -0,0 +1,24 @@
+{ pkgs, ... }:
+
+ with builtins;
+
+let
+ users = [ "tv" ];
+ urxvt = pkgs.rxvt_unicode;
+ mkService = user: {
+ description = "urxvt terminal daemon";
+ wantedBy = [ "multi-user.target" ];
+ restartIfChanged = false;
+ serviceConfig = {
+ Restart = "always";
+ User = user;
+ ExecStart = "${urxvt}/bin/urxvtd";
+ };
+ };
+
+in
+
+{
+ environment.systemPackages = [ urxvt ];
+ systemd.services = listToAttrs (map (u: { name = "${u}-urxvtd"; value = mkService u; }) users);
+}
diff --git a/modules/users.nix b/modules/users.nix
new file mode 100644
index 000000000..eec1defa5
--- /dev/null
+++ b/modules/users.nix
@@ -0,0 +1,226 @@
+{ config, pkgs, ... }:
+
+let
+ inherit (builtins) attrValues;
+ inherit (pkgs.lib) concatMap filterAttrs mapAttrs concatStringsSep;
+
+
+ users = {
+ tv = {
+ uid = 1337;
+ group = "users";
+ extraGroups = [
+ "audio"
+ "video"
+ "wheel"
+ ];
+ };
+
+ ff = {
+ uid = 13378001;
+ group = "tv-sub";
+ extraGroups = [
+ "audio"
+ "video"
+ ];
+ };
+
+ cr = {
+ uid = 13378002;
+ group = "tv-sub";
+ extraGroups = [
+ "audio"
+ "video"
+ "bumblebee"
+ ];
+ };
+
+ vimb = {
+ uid = 13378003;
+ group = "tv-sub";
+ extraGroups = [
+ "audio"
+ "video"
+ "bumblebee"
+ ];
+ };
+
+ fa = {
+ uid = 2300001;
+ group = "tv-sub";
+ };
+
+ rl = {
+ uid = 2300002;
+ group = "tv-sub";
+ };
+
+ btc-bitcoind = {
+ uid = 2301001;
+ group = "tv-sub";
+ };
+
+ btc-electrum = {
+ uid = 2301002;
+ group = "tv-sub";
+ };
+
+ ltc-litecoind = {
+ uid = 2301101;
+ group = "tv-sub";
+ };
+
+ eth = {
+ uid = 2302001;
+ group = "tv-sub";
+ };
+
+ emse-hsdb = {
+ uid = 4200101;
+ group = "tv-sub";
+ };
+
+ wine = {
+ uid = 13370400;
+ group = "tv-sub";
+ extraGroups = [
+ "audio"
+ "video"
+ "bumblebee"
+ ];
+ };
+
+ # dwarffortress
+ df = {
+ uid = 13370401;
+ group = "tv-sub";
+ extraGroups = [
+ "audio"
+ "video"
+ "bumblebee"
+ ];
+ };
+
+ # XXX visudo: Warning: Runas_Alias `FTL' referenced but not defined
+ FTL = {
+ uid = 13370402;
+ #group = "tv-sub";
+ extraGroups = [
+ "audio"
+ "video"
+ "bumblebee"
+ ];
+ };
+
+ freeciv = {
+ uid = 13370403;
+ group = "tv-sub";
+ };
+
+ xr = {
+ uid = 13370061;
+ group = "tv-sub";
+ extraGroups = [
+ "audio"
+ "video"
+ ];
+ };
+
+ "23" = {
+ uid = 13370023;
+ group = "tv-sub";
+ };
+
+ electrum = {
+ uid = 13370102;
+ group = "tv-sub";
+ };
+
+ Reaktor = {
+ uid = 4230010;
+ group = "tv-sub";
+ };
+
+ gitolite = {
+ uid = 7700;
+ };
+
+ skype = {
+ uid = 6660001;
+ group = "tv-sub";
+ extraGroups = [
+ "audio"
+ ];
+ };
+
+ onion = {
+ uid = 6660010;
+ group = "tv-sub";
+ };
+
+ zalora = {
+ uid = 1000301;
+ group = "tv-sub";
+ extraGroups = [
+ "audio"
+ # TODO remove vboxusers when hardening is active
+ "vboxusers"
+ "video"
+ ];
+ };
+
+ };
+
+
+ extraUsers =
+ mapAttrs (name: user: user // {
+ inherit name;
+ home = "/home/${name}";
+ createHome = true;
+ useDefaultShell = true;
+ }) users;
+
+
+ extraGroups = {
+ tv-sub.gid = 1337;
+ };
+
+
+ sudoers =
+ let
+ inherit (builtins) filter hasAttr;
+ inherit (import ../lib { inherit pkgs; }) concat isSuffixOf removeSuffix setToList;
+
+ hasMaster = { group ? "", ... }:
+ isSuffixOf "-sub" group;
+
+ masterOf = user : removeSuffix "-sub" user.group;
+ in
+ concatStringsSep "\n"
+ (map (u: "${masterOf u} ALL=(${u.name}) NOPASSWD: ALL")
+ (filter hasMaster (attrValues extraUsers)));
+
+in
+
+
+{
+ imports = [
+ <secrets/hashedPasswords.nix>
+ ];
+
+ users.defaultUserShell = "/run/current-system/sw/bin/bash";
+ users.extraGroups = extraGroups;
+ users.extraUsers = extraUsers;
+ users.mutableUsers = false;
+
+ #security.sudo.configFile = sudoers config.users.extraUsers;
+ security.sudo.configFile =
+ with builtins; trace
+ ''
+ OK
+ ''
+ sudoers;
+ security.sudo.extraConfig = ''
+ Defaults mailto="tv@wu.retiolum"
+ '';
+}
diff --git a/modules/xserver.nix b/modules/xserver.nix
new file mode 100644
index 000000000..c65201802
--- /dev/null
+++ b/modules/xserver.nix
@@ -0,0 +1,51 @@
+{ config, pkgs, ... }:
+
+{
+ services.xserver.enable = true;
+
+
+ #fonts.enableFontConfig = true;
+ #fonts.enableFontDir = true;
+ fonts.fonts = [
+ pkgs.xlibs.fontschumachermisc
+ ];
+ #services.xfs.enable = true;
+ #services.xserver.useXFS = "unix/:7100";
+
+ services.xserver.displayManager.desktopManagerHandlesLidAndPower = true;
+
+ #services.xserver.display = 11;
+ #services.xserver.tty = 11;
+ # services.xserver.layout = "us";
+ # services.xserver.xkbOptions = "eurosign:e";
+
+ # TODO this is host specific
+ services.xserver.synaptics = {
+ enable = true;
+ twoFingerScroll = true;
+ accelFactor = "0.035";
+ additionalOptions = ''
+ Option "FingerHigh" "60"
+ Option "FingerLow" "60"
+ '';
+ };
+
+ #services.xserver.multitouch.enable = true;
+
+ services.xserver.windowManager.xmonad.extraPackages = hspkgs: with hspkgs; [
+ X11-xshape
+ ];
+ services.xserver.windowManager.xmonad.enable = true;
+ services.xserver.windowManager.xmonad.enableContribAndExtras = true;
+ services.xserver.windowManager.default = "xmonad";
+ services.xserver.desktopManager.default = "none";
+ services.xserver.desktopManager.xterm.enable = false;
+
+ services.xserver.displayManager.slim.enable = true;
+ #services.xserver.displayManager.auto.enable = true;
+ #services.xserver.displayManager.auto.user = "tv";
+ #services.xserver.displayManager.job.logsXsession = true;
+
+
+ services.xserver.vaapiDrivers = [ pkgs.vaapiIntel ];
+}
diff --git a/wu.nix b/wu.nix
new file mode 100644
index 000000000..de435fc3a
--- /dev/null
+++ b/wu.nix
@@ -0,0 +1,457 @@
+{ config, pkgs, ... }:
+
+with (import ./lib { inherit pkgs; });
+
+{
+ imports = [
+ ./modules/base.nix
+ ./modules/retiolum.nix
+ ./modules/urxvt.nix
+ ./modules/iptables.nix
+ ./modules/users.nix
+ ./modules/tools.nix
+ ./modules/hosts.nix
+ ./modules/xserver.nix
+ ./modules/exim.nix
+ ./modules/nginx.nix
+ ];
+
+ services.udev.extraRules = ''
+ SUBSYSTEM=="net", ATTR{address}=="00:90:f5:da:aa:c3", NAME="en0"
+ SUBSYSTEM=="net", ATTR{address}=="a0:88:b4:1b:ae:6c", NAME="wl0"
+
+ # for jack
+ KERNEL=="rtc0", GROUP="audio"
+ KERNEL=="hpet", GROUP="audio"
+ '';
+
+ #services.virtualbox.enable = true;
+ #services.virtualboxGuest.enable = false;
+ services.virtualboxHost.enable = true;
+ #services.virtualboxHost.addNetworkInterface = false;
+ #systemd.services.vboxnet =
+ # let
+ # remove_vboxnets = ''
+ # for i in $(cd /sys/class/net && ls | grep ^vboxnet); do
+ # VBoxManage hostonlyif remove $i
+ # done
+ # '';
+ # in {
+ # wantedBy = [ "multi-user.target" ];
+ # requires = [ "dev-vboxnetctl.device" ];
+ # after = [ "dev-vboxnetctl.device" ];
+ # path = with pkgs; [
+ # linuxPackages.virtualbox
+ # nettools
+ # ];
+ # postStop = remove_vboxnets;
+ # script = ''
+ # ${remove_vboxnets} # just in case...
+ # VBoxManage hostonlyif create # vboxnet0
+ # ifconfig vboxnet0 up 169.254.13.37/16
+ # '';
+ # serviceConfig = {
+ # Type = "oneshot";
+ # PrivateTmp = true;
+ # RemainAfterExit = "yes";
+ # };
+ # environment.VBOX_USER_HOME = "/tmp";
+ # };
+
+
+ services.bitlbee.enable = true;
+
+ #services.rabbitmq = {
+ # enable = true;
+ # cookie = "f00