summary refs log tree commit diff
path: root/modules/services/networking
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2009-10-12 16:36:19 +0000
committerEelco Dolstra <eelco.dolstra@logicblox.com>2009-10-12 16:36:19 +0000
commite91d882a946fc736f62235296e77c139cee7d9b3 (patch)
treee220488319f0cc28aafb01ca26809429eeaf7f82 /modules/services/networking
parent4a78ef25e73da292d060a2afde0c00980a22b2ac (diff)
downloadnixpkgs-e91d882a946fc736f62235296e77c139cee7d9b3.tar
nixpkgs-e91d882a946fc736f62235296e77c139cee7d9b3.tar.gz
nixpkgs-e91d882a946fc736f62235296e77c139cee7d9b3.tar.bz2
nixpkgs-e91d882a946fc736f62235296e77c139cee7d9b3.tar.lz
nixpkgs-e91d882a946fc736f62235296e77c139cee7d9b3.tar.xz
nixpkgs-e91d882a946fc736f62235296e77c139cee7d9b3.tar.zst
nixpkgs-e91d882a946fc736f62235296e77c139cee7d9b3.zip
* Converted modules that were still using the old (concrete syntax)
  style of declaring Upstart jobs.  While at it, converted them to the
  current NixOS module style and improved some option descriptions.
  Hopefully I didn't break too much :-)

svn path=/nixos/trunk/; revision=17761
Diffstat (limited to 'modules/services/networking')
-rw-r--r--modules/services/networking/avahi-daemon.nix236
-rw-r--r--modules/services/networking/bind.nix212
-rw-r--r--modules/services/networking/bitlbee.nix132
-rw-r--r--modules/services/networking/dhcpd.nix208
-rw-r--r--modules/services/networking/ejabberd.nix138
-rw-r--r--modules/services/networking/gnunet.nix336
-rw-r--r--modules/services/networking/gw6c.nix252
-rw-r--r--modules/services/networking/ircd-hybrid.nix215
-rw-r--r--modules/services/networking/openfire.nix100
-rw-r--r--modules/services/networking/openvpn.nix188
-rw-r--r--modules/services/networking/portmap.nix121
-rw-r--r--modules/services/networking/ssh/lshd.nix284
-rw-r--r--modules/services/networking/vsftpd.nix237
13 files changed, 1300 insertions, 1359 deletions
diff --git a/modules/services/networking/avahi-daemon.nix b/modules/services/networking/avahi-daemon.nix
index ff01a755f6a..34e2a83754d 100644
--- a/modules/services/networking/avahi-daemon.nix
+++ b/modules/services/networking/avahi-daemon.nix
@@ -1,86 +1,18 @@
 # Avahi daemon.
-{pkgs, config, ...}:
+{ config, pkgs, ... }:
 
-###### interface
-let
-  inherit (pkgs.lib) mkOption;
-
-  options = {
-    services = {
-      avahi = {
-
-        enable = mkOption {
-          default = false;
-          description = ''
-            Whether to run the Avahi daemon, which allows Avahi clients
-            to use Avahi's service discovery facilities and also allows
-            the local machine to advertise its presence and services
-            (through the mDNS responder implemented by `avahi-daemon').
-          '';
-        };
+with pkgs.lib;
 
-        hostName = mkOption {
-          default = config.networking.hostName;
-          description = ''Host name advertised on the LAN.'';
-        };
-
-        browseDomains = mkOption {
-          default = [ "0pointer.de" "zeroconf.org" ];
-          description = ''
-            List of non-local DNS domains to be browsed.
-          '';
-        };
-
-        ipv4 = mkOption {
-          default = true;
-          description = ''Whether to use IPv4'';
-        };
-
-        ipv6 = mkOption {
-          default = false;
-          description = ''Whether to use IPv6'';
-        };
-
-        wideArea = mkOption {
-          default = true;
-          description = ''Whether to enable wide-area service discovery.'';
-        };
-
-        publishing = mkOption {
-          default = true;
-          description = ''Whether to allow publishing.'';
-        };
-
-        nssmdns = mkOption {
-          default = false;
-          description = ''
-            Whether to enable the mDNS NSS (Name Service Switch) plug-in.
-            Enabling it allows applications to resolve names in the `.local'
-            domain by transparently querying the Avahi daemon.
-
-            Warning: Currently, enabling this option breaks DNS lookups after
-            a `nixos-rebuild'.  This is because `/etc/nsswitch.conf' is
-            updated to use `nss-mdns' but `libnss_mdns' is not in
-            applications' `LD_LIBRARY_PATH'.  The next time `/etc/profile' is
-            sourced, it will set up an appropriate `LD_LIBRARY_PATH', though.
-          '';
-        };
-      };
-    };
-  };
-in
-
-###### implementation
 let
+
   cfg = config.services.avahi;
-  inherit (pkgs.lib) mkIf mkThenElse;
 
-  inherit (pkgs) avahi writeText lib;
+  inherit (pkgs) avahi;
 
-  avahiDaemonConf = with cfg; writeText "avahi-daemon.conf" ''
+  avahiDaemonConf = with cfg; pkgs.writeText "avahi-daemon.conf" ''
     [server]
     host-name=${hostName}
-    browse-domains=${lib.concatStringsSep ", " browseDomains}
+    browse-domains=${concatStringsSep ", " browseDomains}
     use-ipv4=${if ipv4 then "yes" else "no"}
     use-ipv6=${if ipv6 then "yes" else "no"}
 
@@ -91,69 +23,119 @@ let
     disable-publishing=${if publishing then "no" else "yes"}
   '';
 
-  user = {
-    name = "avahi";
-    uid = config.ids.uids.avahi;
-    description = "`avahi-daemon' privilege separation user";
-    home = "/var/empty";
-  };
+in
 
-  group = {
-    name = "avahi";
-    gid = config.ids.gids.avahi;
-  };
+{
 
-  job = {
-    name = "avahi-daemon";
+  ###### interface
 
-    job = ''
-      start on network-interfaces/started
-      stop on network-interfaces/stop
-      respawn
-      script
-        export PATH="${avahi}/bin:${avahi}/sbin:$PATH"
+  options = {
+  
+    services.avahi = {
+
+      enable = mkOption {
+        default = false;
+        description = ''
+          Whether to run the Avahi daemon, which allows Avahi clients
+          to use Avahi's service discovery facilities and also allows
+          the local machine to advertise its presence and services
+          (through the mDNS responder implemented by `avahi-daemon').
+        '';
+      };
 
-        # Make NSS modules visible so that `avahi_nss_support ()' can
-        # return a sensible value.
-        export LD_LIBRARY_PATH="${config.system.nssModules.path}"
+      hostName = mkOption {
+        default = config.networking.hostName;
+        description = ''Host name advertised on the LAN.'';
+      };
 
-        exec ${avahi}/sbin/avahi-daemon --daemonize -f "${avahiDaemonConf}"
-      end script
-    '';
-  };
-in
+      browseDomains = mkOption {
+        default = [ "0pointer.de" "zeroconf.org" ];
+        description = ''
+          List of non-local DNS domains to be browsed.
+        '';
+      };
 
-mkIf cfg.enable {
-  require = [
-    # ../upstart-jobs/default.nix # config.services.extraJobs
-    # ../system/? # system.nssModules
-    # ? # config.environment.etc
-    # ../system/user.nix # users.*
-    # ../upstart-jobs/udev.nix # services.udev.*
-    # ../upstart-jobs/dbus.nix # services.dbus.*
-    # ? # config.environment.extraPackages
-    options
-  ];
-
-  system = {
-    nssModules = pkgs.lib.optional cfg.nssmdns pkgs.nssmdns;
-  };
+      ipv4 = mkOption {
+        default = true;
+        description = ''Whether to use IPv4'';
+      };
 
-  environment = {
-    systemPackages = [avahi];
-  };
+      ipv6 = mkOption {
+        default = false;
+        description = ''Whether to use IPv6'';
+      };
 
-  users = {
-    extraUsers = [user];
-    extraGroups = [group];
-  };
+      wideArea = mkOption {
+        default = true;
+        description = ''Whether to enable wide-area service discovery.'';
+      };
 
-  services = {
-    extraJobs = [job];
+      publishing = mkOption {
+        default = true;
+        description = ''Whether to allow publishing.'';
+      };
 
-    dbus = {
-      enable = true;
-      packages = [avahi];
+      nssmdns = mkOption {
+        default = false;
+        description = ''
+          Whether to enable the mDNS NSS (Name Service Switch) plug-in.
+          Enabling it allows applications to resolve names in the `.local'
+          domain by transparently querying the Avahi daemon.
+
+          Warning: Currently, enabling this option breaks DNS lookups after
+          a `nixos-rebuild'.  This is because `/etc/nsswitch.conf' is
+          updated to use `nss-mdns' but `libnss_mdns' is not in
+          applications' `LD_LIBRARY_PATH'.  The next time `/etc/profile' is
+          sourced, it will set up an appropriate `LD_LIBRARY_PATH', though.
+        '';
+      };
+      
     };
+    
+  };
+  
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    users.extraUsers = singleton
+      { name = "avahi";
+        uid = config.ids.uids.avahi;
+        description = "`avahi-daemon' privilege separation user";
+        home = "/var/empty";
+      };
+
+    users.extraGroups = singleton
+      { name = "avahi";
+        gid = config.ids.gids.avahi;
+      };
+
+    system.nssModules = optional cfg.nssmdns pkgs.nssmdns;
+
+    environment.systemPackages = [ avahi ];
+
+    jobAttrs.avahi_daemon =
+      { name = "avahi-daemon";
+
+        startOn = "network-interfaces/started";
+        stopOn = "network-interfaces/stop";
+
+        script =
+          ''
+            export PATH="${avahi}/bin:${avahi}/sbin:$PATH"
+
+            # Make NSS modules visible so that `avahi_nss_support ()' can
+            # return a sensible value.
+            export LD_LIBRARY_PATH="${config.system.nssModules.path}"
+
+            exec ${avahi}/sbin/avahi-daemon --daemonize -f "${avahiDaemonConf}"
+          '';
+      };
+
+    services.dbus.enable = true;
+    services.dbus.packages = [avahi];
+
   };
+
 }
diff --git a/modules/services/networking/bind.nix b/modules/services/networking/bind.nix
index d216987e573..d1a137f3502 100644
--- a/modules/services/networking/bind.nix
+++ b/modules/services/networking/bind.nix
@@ -1,123 +1,121 @@
-{pkgs, config, ...}:
+{ config, pkgs, ... }:
+
+with pkgs.lib;
 
-###### interface
 let
-  inherit (pkgs.lib) mkOption mkIf;
 
-  options = {
-    services = {
-      bind = {
-        enable = mkOption {
-          default = false;
-          description = "
-            Whether to enable BIND domain name server.
-          ";
-        };
-        cacheNetworks = mkOption {
-          default = ["127.0.0.0/24"];
-          description = "
-            What networks are allowed to use us as a resolver.
-          ";
-        };
-        blockedNetworks = mkOption {
-          default = [];
-          description = "
-            What networks are just blocked.
-          ";
-        };
-        zones = mkOption {
-          default = [];
-          description = "
-            List of zones we claim authority over.
-              master=false means slave server; slaves means addresses 
-             who may request zone transfer.
-          ";
-          example = [{
-            name = "example.com";
-            master = false;
-            file = "/var/dns/example.com";
-            masters = ["192.168.0.1"];
-            slaves = [];
-          }];
-        };
+  startingDependency = if config.services.gw6c.enable then "gw6c" else "network-interfaces";
+  
+  cfg = config.services.bind;
+
+  confFile = pkgs.writeText "named.conf"
+    ''
+      acl cachenetworks { ${concatMapStrings (entry: " ${entry}; ") cfg.cacheNetworks} };
+      acl badnetworks { ${concatMapStrings (entry: " ${entry}; ") cfg.blockedNetworks} };
+
+      options {
+        listen-on {any;};
+        listen-on-v6 {any;};
+        allow-query { cachenetworks; };
+        blackhole { badnetworks; };
+        forward first;
+        forwarders { ${concatMapStrings (entry: " ${entry}; ") config.networking.nameservers} };
+        directory "/var/run/named";
+        pid-file "/var/run/named/named.pid";
       };
-    };
-  };
+
+      ${ concatMapStrings
+          ({ name, file, master ? true, slaves ? [], masters ? [] }:
+            ''           
+              zone "${name}" {
+                type ${if master then "master" else "slave"};
+                file "${file}";
+                ${ if master then
+                   ''
+                     allow-transfer {
+                       ${concatMapStrings (ip: "${ip};\n") slaves}
+                     };
+                   ''
+                   else
+                   ''
+                     masters {
+                       ${concatMapStrings (ip: "${ip};\n") masters}
+                     };
+                   ''
+                }
+                allow-query { any; };
+              };
+            '')
+          cfg.zones }
+    '';
+
 in
 
-###### implementation
+{
 
-let
-  startingDependency = if config.services.gw6c.enable then "gw6c" else "network-interfaces";
-  cfg = config.services.bind;
-  concatMapStrings = pkgs.lib.concatMapStrings;
-
-  namedConf = 
-  (''
-    acl cachenetworks { ${concatMapStrings (entry: " ${entry}; ") cfg.cacheNetworks} };
-    acl badnetworks { ${concatMapStrings (entry: " ${entry}; ") cfg.blockedNetworks} };
-
-    options {
-      listen-on {any;};
-      listen-on-v6 {any;};
-      allow-query { cachenetworks; };
-      blackhole { badnetworks; };
-      forward first;
-      forwarders { ${concatMapStrings (entry: " ${entry}; ") config.networking.nameservers} };
-      directory "/var/run/named";
-      pid-file "/var/run/named/named.pid";
+  ###### interface
+
+  options = {
+  
+    services.bind = {
+    
+      enable = mkOption {
+        default = false;
+        description = "
+          Whether to enable BIND domain name server.
+        ";
+      };
+      
+      cacheNetworks = mkOption {
+        default = ["127.0.0.0/24"];
+        description = "
+          What networks are allowed to use us as a resolver.
+        ";
+      };
+      
+      blockedNetworks = mkOption {
+        default = [];
+        description = "
+          What networks are just blocked.
+        ";
+      };
+      
+      zones = mkOption {
+        default = [];
+        description = "
+          List of zones we claim authority over.
+            master=false means slave server; slaves means addresses 
+           who may request zone transfer.
+        ";
+        example = [{
+          name = "example.com";
+          master = false;
+          file = "/var/dns/example.com";
+          masters = ["192.168.0.1"];
+          slaves = [];
+        }];
+      };
+      
     };
 
-  '')
-  + 
-  (concatMapStrings 
-    (_entry:let entry={master=true;slaves=[];masters=[];}//_entry; in
-      ''
-        zone "${entry.name}" {
-          type ${if entry.master then "master" else "slave"};
-          file "${entry.file}";
-          ${ if entry.master then
-             ''
-               allow-transfer {
-                 ${concatMapStrings (ip: ip+";\n") entry.slaves}
-               };
-             ''
-             else
-             ''
-               masters {
-                 ${concatMapStrings (ip: ip+";\n") entry.masters}
-               };
-             ''
-          }
-          allow-query { any; };
-        };
-      ''
-    )
-    cfg.zones
-  )
-  ;
-
-  confFile = pkgs.writeText "named.conf" namedConf;
+  };
+  
 
-in
+  ###### implementation
 
-mkIf config.services.bind.enable {
-  require = [
-    options
-  ];
+  config = mkIf config.services.bind.enable {
 
-  services = {
-    extraJobs = [{
-      name = "bind";
-      job = ''
-        description "BIND name server job"
+    jobAttrs.bind =
+      { description = "BIND name server job";
 
-        start script
-          ${pkgs.coreutils}/bin/mkdir -p /var/run/named
-        end script
+        preStart =
+          ''
+            ${pkgs.coreutils}/bin/mkdir -p /var/run/named
+          '';
+
+        exec = "${pkgs.bind}/sbin/named -c ${confFile} -f";
+      };
 
-        respawn ${pkgs.bind}/sbin/named -c ${confFile} -f 
-      '';
-    }];
   };
+  
 }
diff --git a/modules/services/networking/bitlbee.nix b/modules/services/networking/bitlbee.nix
index 9e07858f949..c55adb49335 100644
--- a/modules/services/networking/bitlbee.nix
+++ b/modules/services/networking/bitlbee.nix
@@ -1,91 +1,93 @@
-{pkgs, config, ...}:
+{ config, pkgs, ... }:
+
+with pkgs.lib;
 
-###### interface
 let
-  inherit (pkgs.lib) mkOption mkIf;
+
+  bitlbeeUid = config.ids.uids.bitlbee;
+  
+  inherit (config.services.bitlbee) portNumber interface;
+  
+in
+
+{
+
+  ###### interface
 
   options = {
-    services = {
-      bitlbee = {
-
-        enable = mkOption {
-          default = false;
-          description = ''
-            Whether to run the BitlBee IRC to other chat network gateway.
-            Running it allows you to access the MSN, Jabber, Yahoo! and ICQ chat
-            networks via an IRC client.
-          '';
-        };
-
-        interface = mkOption {
-          default = "127.0.0.1";
-          description = ''
-            The interface the BitlBee deamon will be listening to.  If `127.0.0.1',
-            only clients on the local host can connect to it; if `0.0.0.0', clients
-            can access it from any network interface.
-          '';
-        };
+  
+    services.bitlbee = {
+
+      enable = mkOption {
+        default = false;
+        description = ''
+          Whether to run the BitlBee IRC to other chat network gateway.
+          Running it allows you to access the MSN, Jabber, Yahoo! and ICQ chat
+          networks via an IRC client.
+        '';
+      };
 
-        portNumber = mkOption {
-          default = 6667;
-          description = ''
-            Number of the port BitlBee will be listening to.
-          '';
-        };
+      interface = mkOption {
+        default = "127.0.0.1";
+        description = ''
+          The interface the BitlBee deamon will be listening to.  If `127.0.0.1',
+          only clients on the local host can connect to it; if `0.0.0.0', clients
+          can access it from any network interface.
+        '';
+      };
 
+      portNumber = mkOption {
+        default = 6667;
+        description = ''
+          Number of the port BitlBee will be listening to.
+        '';
       };
-    };
-  };
-in
 
-###### implementation
+    };
 
-let
-  bitlbeeUid = config.ids.uids.bitlbee;
-  inherit (config.services.bitlbee) portNumber interface;
-in
+  };
+  
 
-mkIf config.services.bitlbee.enable {
+  ###### implementation
 
-  require = options;
+  config = mkIf config.services.bitlbee.enable {
 
-  users = {
-    extraUsers = [
+    users.extraUsers = singleton
       { name = "bitlbee";
         uid = bitlbeeUid;
         description = "BitlBee user";
         home = "/var/empty";
-      }
-    ];
+      };
     
-    extraGroups = [
+    users.extraGroups = singleton
       { name = "bitlbee";
         gid = config.ids.gids.bitlbee;
-      }
-    ];
-  };
-
-  services.extraJobs = [{
-    name = "bitlbee";
+      };
 
-    job = ''
-      description "BitlBee IRC to other chat networks gateway"
+    jobAttrs.bitlbee =
+      { description = "BitlBee IRC to other chat networks gateway";
 
-      start on network-interfaces/started
-      stop on network-interfaces/stop
+        startOn = "network-interfaces/started";
+        stopOn = "network-interfaces/stop";
 
-      start script
-          if ! test -d /var/lib/bitlbee
-          then
-              mkdir -p /var/lib/bitlbee
-              chown bitlbee:bitlbee /var/lib/bitlbee
-          fi
-      end script
+        preStart =
+          ''
+            if ! test -d /var/lib/bitlbee
+            then
+                mkdir -p /var/lib/bitlbee
+                chown bitlbee:bitlbee /var/lib/bitlbee
+            fi
+          '';
 
-      respawn ${pkgs.bitlbee}/sbin/bitlbee -F -p ${toString portNumber} \
+        exec =
+          ''
+            ${pkgs.bitlbee}/sbin/bitlbee -F -p ${toString portNumber} \
               -i ${interface} -u bitlbee
-    '';
-  }];
+          '';
+      };
+
+    environment.systemPackages = [ pkgs.bitlbee ];
 
-  environment.systemPackages = [ pkgs.bitlbee ];
+  };
+  
 }
diff --git a/modules/services/networking/dhcpd.nix b/modules/services/networking/dhcpd.nix
index 9604dd965b9..5a2d9034dfd 100644
--- a/modules/services/networking/dhcpd.nix
+++ b/modules/services/networking/dhcpd.nix
@@ -1,123 +1,121 @@
-{pkgs, config, ...}:
+{ config, pkgs, ... }:
+
+with pkgs.lib;
 
-###### interface
 let
-  inherit (pkgs.lib) mkOption mkIf;
 
-  options = {
-    services = {
-      dhcpd = {
-
-        enable = mkOption {
-          default = false;
-          description = "
-            Whether to enable the DHCP server.
-          ";
-        };
-
-        extraConfig = mkOption {
-          default = "";
-          example = "
-            option subnet-mask 255.255.255.0;
-            option broadcast-address 192.168.1.255;
-            option routers 192.168.1.5;
-            option domain-name-servers 130.161.158.4, 130.161.33.17, 130.161.180.1;
-            option domain-name \"example.org\";
-            subnet 192.168.1.0 netmask 255.255.255.0 {
-              range 192.168.1.100 192.168.1.200;
-            }
-          ";
-          description = "
-            Extra text to be appended to the DHCP server configuration
-            file.  Currently, you almost certainly need to specify
-            something here, such as the options specifying the subnet
-            mask, DNS servers, etc.
-          ";
-        };
-
-        configFile = mkOption {
-          default = null;
-          description = "
-            The path of the DHCP server configuration file.  If no file
-            is specified, a file is generated using the other options.
-          ";
-        };
-
-        interfaces = mkOption {
-          default = ["eth0"];
-          description = "
-            The interfaces on which the DHCP server should listen.
-          ";
-        };
-
-        machines = mkOption {
-          default = [];
-          example = [
-            { hostName = "foo";
-              ethernetAddress = "00:16:76:9a:32:1d";
-              ipAddress = "192.168.1.10";
-            }
-            { hostName = "bar";
-              ethernetAddress = "00:19:d1:1d:c4:9a";
-              ipAddress = "192.168.1.11";
+  cfg = config.services.dhcpd;
+
+  stateDir = "/var/lib/dhcp"; # Don't use /var/state/dhcp; not FHS-compliant.
+
+  configFile = if cfg.configFile != null then cfg.configFile else pkgs.writeText "dhcpd.conf"
+    ''
+      default-lease-time 600;
+      max-lease-time 7200;
+      authoritative;
+      ddns-update-style ad-hoc;
+      log-facility local1; # see dhcpd.nix
+      
+      ${cfg.extraConfig}
+
+      ${pkgs.lib.concatMapStrings
+          (machine: ''
+            host ${machine.hostName} {
+              hardware ethernet ${machine.ethernetAddress};
+              fixed-address ${machine.ipAddress};
             }
-          ];
-          description = "
-            A list mapping ethernet addresses to IP addresses for the
-            DHCP server.
-          ";
-        };
+          '')
+          cfg.machines
+      }
+    '';
 
-      };
-    };
-  };
 in
+  
+{
 
-###### implementation
+  ###### interface
 
-let
+  options = {
+  
+    services.dhcpd = {
 
-  cfg = config.services.dhcpd;
+      enable = mkOption {
+        default = false;
+        description = "
+          Whether to enable the DHCP server.
+        ";
+      };
 
-  stateDir = "/var/lib/dhcp"; # Don't use /var/state/dhcp; not FHS-compliant.
+      extraConfig = mkOption {
+        default = "";
+        example = "
+          option subnet-mask 255.255.255.0;
+          option broadcast-address 192.168.1.255;
+          option routers 192.168.1.5;
+          option domain-name-servers 130.161.158.4, 130.161.33.17, 130.161.180.1;
+          option domain-name \"example.org\";
+          subnet 192.168.1.0 netmask 255.255.255.0 {
+            range 192.168.1.100 192.168.1.200;
+          }
+        ";
+        description = "
+          Extra text to be appended to the DHCP server configuration
+          file.  Currently, you almost certainly need to specify
+          something here, such as the options specifying the subnet
+          mask, DNS servers, etc.
+        ";
+      };
 
-  machines = pkgs.lib.concatMapStrings (machine: ''
-    host ${machine.hostName} {
-      hardware ethernet ${machine.ethernetAddress};
-      fixed-address ${machine.ipAddress};
-    }
-  '') cfg.machines;
-
-  configFile = if cfg.configFile != null then cfg.configFile else pkgs.writeText "dhcpd.conf" ''
-    default-lease-time 600;
-    max-lease-time 7200;
-    authoritative;
-    ddns-update-style ad-hoc;
-    log-facility local1; # see dhcpd.nix
-    ${cfg.extraConfig}
-    ${machines}
-  '';
+      configFile = mkOption {
+        default = null;
+        description = "
+          The path of the DHCP server configuration file.  If no file
+          is specified, a file is generated using the other options.
+        ";
+      };
 
-in
+      interfaces = mkOption {
+        default = ["eth0"];
+        description = "
+          The interfaces on which the DHCP server should listen.
+        ";
+      };
+
+      machines = mkOption {
+        default = [];
+        example = [
+          { hostName = "foo";
+            ethernetAddress = "00:16:76:9a:32:1d";
+            ipAddress = "192.168.1.10";
+          }
+          { hostName = "bar";
+            ethernetAddress = "00:19:d1:1d:c4:9a";
+            ipAddress = "192.168.1.11";
+          }
+        ];
+        description = "
+          A list mapping ethernet addresses to IP addresses for the
+          DHCP server.
+        ";
+      };
+
+    };
+    
+  };
   
 
-mkIf config.services.dhcpd.enable {
-  require = [
-    options
-  ];
+  ###### implementation
 
-  services = {
-    extraJobs = [{
-      name = "dhcpd";
-      
-      job = ''
-        description "DHCP server"
+  config = mkIf config.services.dhcpd.enable {
 
-        start on network-interfaces/started
-        stop on network-interfaces/stop
+    jobAttrs.dhcpd =
+      { description = "DHCP server";
 
-        script
+        startOn = "network-interfaces/started";
+        stopOn = "network-interfaces/stop";
 
+        script =
+          ''
             mkdir -m 755 -p ${stateDir}
 
             touch ${stateDir}/dhcpd.leases
@@ -125,9 +123,9 @@ mkIf config.services.dhcpd.enable {
             exec ${pkgs.dhcp}/sbin/dhcpd -f -cf ${configFile} \
                 -lf ${stateDir}/dhcpd.leases \
                 ${toString cfg.interfaces}
+          '';
+      };
 
-        end script
-      '';
-    }];
   };
+  
 }
diff --git a/modules/services/networking/ejabberd.nix b/modules/services/networking/ejabberd.nix
index b1f485cf1c8..8ef910e1262 100644
--- a/modules/services/networking/ejabberd.nix
+++ b/modules/services/networking/ejabberd.nix
@@ -1,85 +1,83 @@
-{pkgs, config, ...}:
+{ config, pkgs, ... }:
+
+with pkgs.lib;
 
-###### interface
 let
-  inherit (pkgs.lib) mkOption mkIf;
+
+  cfg = config.services.ejabberd;
+
+in
+
+{
+
+  ###### interface
 
   options = {
-    services = {
-      ejabberd = {
-        enable = mkOption {
-          default = false;
-          description = "Whether to enable ejabberd server";
-        };
-              
-        spoolDir = mkOption {
-          default = "/var/lib/ejabberd";
-          description = "Location of the spooldir of ejabberd";
-        };
-        
-        logsDir = mkOption {
-          default = "/var/log/ejabberd";
-          description = "Location of the logfile directory of ejabberd";
-        };
-        
-        confDir = mkOption {
-          default = "/var/ejabberd";
-          description = "Location of the config directory of ejabberd";
-        };
-        
-        virtualHosts = mkOption {
-          default = "\"localhost\"";
-          description = "Virtualhosts that ejabberd should host. Hostnames are surrounded with doublequotes and separated by commas";
-        };
+  
+    services.ejabberd = {
+    
+      enable = mkOption {
+        default = false;
+        description = "Whether to enable ejabberd server";
+      };
+
+      spoolDir = mkOption {
+        default = "/var/lib/ejabberd";
+        description = "Location of the spooldir of ejabberd";
+      };
+
+      logsDir = mkOption {
+        default = "/var/log/ejabberd";
+        description = "Location of the logfile directory of ejabberd";
+      };
+
+      confDir = mkOption {
+        default = "/var/ejabberd";
+        description = "Location of the config directory of ejabberd";
       };
+
+      virtualHosts = mkOption {
+        default = "\"localhost\"";
+        description = "Virtualhosts that ejabberd should host. Hostnames are surrounded with doublequotes and separated by commas";
+      };
+
     };
+    
   };
-in
+  
 
-###### implementation
+  ###### implementation
 
-let
+  config = mkIf cfg.enable {
 
-cfg = config.services.ejabberd;
+    jobAttrs.ejabberd =
+      { description = "EJabberd server";
 
-in
+        startOn = "network-interface/started";
+        stopOn = "network-interfaces/stop";
 
-mkIf config.services.ejabberd.enable {
-
-  require = [
-    options
-  ];
-
-
-  services = {
-    extraJobs = [{
-      name = "ejabberd";
-          
-      job = ''
-        description "EJabberd server"
-
-        start on network-interface/started
-        stop on network-interfaces/stop
-      
-        start script
-              # Initialise state data
-              mkdir -p ${cfg.logsDir}
-              
-              if ! test -d ${cfg.spoolDir}
-              then
-                  cp -av ${pkgs.ejabberd}/var/lib/ejabberd /var/lib
-              fi
-              
-              mkdir -p ${cfg.confDir}
-              test -f ${cfg.confDir}/ejabberd.cfg || sed -e 's|{hosts, \["localhost"\]}.|{hosts, \[${cfg.virtualHosts}\]}.|' ${pkgs.ejabberd}/etc/ejabberd/ejabberd.cfg > ${cfg.confDir}/ejabberd.cfg
-        end script
-        
-        respawn ${pkgs.bash}/bin/sh -c 'export PATH=$PATH:${pkgs.ejabberd}/sbin:${pkgs.coreutils}/bin:${pkgs.bash}/bin; cd ~; ejabberdctl --logs ${cfg.logsDir} --spool ${cfg.spoolDir} --config ${cfg.confDir}/ejabberd.cfg start; sleep 1d'
-        
-        stop script
+        preStart =
+          ''
+            # Initialise state data
+            mkdir -p ${cfg.logsDir}
+
+            if ! test -d ${cfg.spoolDir}
+            then
+                cp -av ${pkgs.ejabberd}/var/lib/ejabberd /var/lib
+            fi
+
+            mkdir -p ${cfg.confDir}
+            test -f ${cfg.confDir}/ejabberd.cfg || sed -e 's|{hosts, \["localhost"\]}.|{hosts, \[${cfg.virtualHosts}\]}.|' ${pkgs.ejabberd}/etc/ejabberd/ejabberd.cfg > ${cfg.confDir}/ejabberd.cfg
+          '';
+
+        exec = "${pkgs.bash}/bin/sh -c 'export PATH=$PATH:${pkgs.ejabberd}/sbin:${pkgs.coreutils}/bin:${pkgs.bash}/bin; cd ~; ejabberdctl --logs ${cfg.logsDir} --spool ${cfg.spoolDir} --config ${cfg.confDir}/ejabberd.cfg start; sleep 1d'";
+
+        postStop =
+          ''        
             ${pkgs.ejabberd}/sbin/ejabberdctl stop
-        end script
-      '';
-    }];
+          '';
+      };
+
   };
+  
 }
diff --git a/modules/services/networking/gnunet.nix b/modules/services/networking/gnunet.nix
index 57e3b3d8c96..05956f74612 100644
--- a/modules/services/networking/gnunet.nix
+++ b/modules/services/networking/gnunet.nix
@@ -1,218 +1,218 @@
-{pkgs, config, ...}:
+{ config, pkgs, ... }:
+
+with pkgs.lib;
 
-###### interface
 let
-  inherit (pkgs.lib) mkOption mkIf;
+
+  cfg = config.services.gnunet;
+
+  configFile = with cfg; pkgs.writeText "gnunetd.conf"
+    ''
+      [PATHS]
+      GNUNETD_HOME = ${home}
+
+      [GNUNETD]
+      HOSTLISTURL = ${lib.concatStringsSep " " hostLists}
+      APPLICATIONS = ${lib.concatStringsSep " " applications}
+      TRANSPORTS = ${lib.concatStringsSep " " transports}
+
+      [LOAD]
+      MAXNETDOWNBPSTOTAL = ${toString load.maxNetDownBandwidth}
+      MAXNETUPBPSTOTAL = ${toString load.maxNetUpBandwidth}
+      HARDUPLIMIT = ${toString load.hardNetUpBandwidth}
+      MAXCPULOAD = ${toString load.maxCPULoad}
+      INTERFACES = ${lib.concatStringsSep " " load.interfaces}
+
+      [FS]
+      QUOTA = ${toString fileSharing.quota}
+      ACTIVEMIGRATION = ${if fileSharing.activeMigration then "YES" else "NO"}
+
+      [MODULES]
+      sqstore = sqstore_sqlite
+      dstore = dstore_sqlite
+      topology = topology_default
+
+      ${extraOptions}
+    '';
+
+in
+
+{
+
+  ###### interface
 
   options = {
-    services = {
-      gnunet = {
+  
+    services.gnunet = {
       
-        enable = mkOption {
-          default = false;
-          description = ''
-            Whether to run the GNUnet daemon.  GNUnet is GNU's anonymous
-            peer-to-peer communication and file sharing framework.
-          '';
-        };
+      enable = mkOption {
+        default = false;
+        description = ''
+          Whether to run the GNUnet daemon.  GNUnet is GNU's anonymous
+          peer-to-peer communication and file sharing framework.
+        '';
+      };
 
-        home = mkOption {
-          default = "/var/lib/gnunet";
+      home = mkOption {
+        default = "/var/lib/gnunet";
+        description = ''
+          Directory where the GNUnet daemon will store its data.
+        '';
+      };
+
+      debug = mkOption {
+        default = false;
+        description = ''
+          When true, run in debug mode; gnunetd will not daemonize and
+          error messages will be written to stderr instead of a
+          logfile.
+        '';
+      };
+
+      logLevel = mkOption {
+        default = "ERROR";
+        example = "INFO";
+        description = ''
+          Log level of the deamon (see `gnunetd(1)' for details).
+        '';
+      };
+
+      hostLists = mkOption {
+        default = [
+          "http://gnunet.org/hostlist.php"
+          "http://gnunet.mine.nu:8081/hostlist"
+          "http://vserver1236.vserver-on.de/hostlist-074"
+        ];
+        description = ''
+          URLs of host lists.
+        '';
+      };
+
+      applications = mkOption {
+        default = [ "advertising" "getoption" "fs" "stats" "traffic" ];
+        example = [ "chat" "fs" ];
+        description = ''
+          List of GNUnet applications supported by the daemon.  Note that
+          `fs', which means "file sharing", is probably the one you want.
+        '';
+      };
+
+      transports = mkOption {
+        default = [ "udp" "tcp" "http" "nat" ];
+        example = [ "smtp" "http" ];
+        description = ''
+          List of transport methods used by the server.
+        '';
+      };
+
+      fileSharing = {
+        quota = mkOption {
+          default = 1024;
           description = ''
-            Directory where the GNUnet daemon will store its data.
+            Maximum file system usage (in MiB) for file sharing.
           '';
         };
 
-        debug = mkOption {
+        activeMigration = mkOption {
           default = false;
           description = ''
-            When true, run in debug mode; gnunetd will not daemonize and
-            error messages will be written to stderr instead of a
-            logfile.
+            Whether to allow active migration of content originating
+            from other nodes.
           '';
         };
+      };
 
-        logLevel = mkOption {
-          default = "ERROR";
-          example = "INFO";
+      load = {
+        maxNetDownBandwidth = mkOption {
+          default = 50000;
           description = ''
-            Log level of the deamon (see `gnunetd(1)' for details).
+            Maximum bandwidth usage (in bits per second) for GNUnet
+            when downloading data.
           '';
         };
 
-        hostLists = mkOption {
-          default = [
-            "http://gnunet.org/hostlist.php"
-            "http://gnunet.mine.nu:8081/hostlist"
-            "http://vserver1236.vserver-on.de/hostlist-074"
-          ];
+        maxNetUpBandwidth = mkOption {
+          default = 50000;
           description = ''
-            URLs of host lists.
+            Maximum bandwidth usage (in bits per second) for GNUnet
+            when downloading data.
           '';
         };
 
-
-        applications = mkOption {
-          default = [ "advertising" "getoption" "fs" "stats" "traffic" ];
-          example = [ "chat" "fs" ];
+        hardNetUpBandwidth = mkOption {
+          default = 0;
           description = ''
-            List of GNUnet applications supported by the daemon.  Note that
-            `fs', which means "file sharing", is probably the one you want.
+            Hard bandwidth limit (in bits per second) when uploading
+            data.
           '';
         };
 
-        transports = mkOption {
-          default = [ "udp" "tcp" "http" "nat" ];
-          example = [ "smtp" "http" ];
+        maxCPULoad = mkOption {
+          default = 100;
           description = ''
-            List of transport methods used by the server.
+            Maximum CPU load (percentage) authorized for the GNUnet
+            daemon.
           '';
         };
 
-        fileSharing = {
-          quota = mkOption {
-            default = 1024;
-            description = ''
-              Maximum file system usage (in MiB) for file sharing.
-            '';
-          };
-
-          activeMigration = mkOption {
-            default = false;
-            description = ''
-              Whether to allow active migration of content originating
-              from other nodes.
-            '';
-          };
-        };
-
-        load = {
-          maxNetDownBandwidth = mkOption {
-            default = 50000;
-            description = ''
-              Maximum bandwidth usage (in bits per second) for GNUnet
-              when downloading data.
-            '';
-          };
-
-          maxNetUpBandwidth = mkOption {
-            default = 50000;
-            description = ''
-              Maximum bandwidth usage (in bits per second) for GNUnet
-              when downloading data.
-            '';
-          };
-
-          hardNetUpBandwidth = mkOption {
-            default = 0;
-            description = ''
-              Hard bandwidth limit (in bits per second) when uploading
-              data.
-            '';
-          };
-
-          maxCPULoad = mkOption {
-            default = 100;
-            description = ''
-              Maximum CPU load (percentage) authorized for the GNUnet
-              daemon.
-            '';
-          };
-
-          interfaces = mkOption {
-            default = [ "eth0" ];
-            example = [ "wlan0" "eth1" ];
-            description = ''
-              List of network interfaces to use.
-            '';
-          };
-        };
-
-        extraOptions = mkOption {
-          default = "";
-          example = ''
-            [NETWORK]
-            INTERFACE = eth3
-          '';
+        interfaces = mkOption {
+          default = [ "eth0" ];
+          example = [ "wlan0" "eth1" ];
           description = ''
-            Additional options that will be copied verbatim in `gnunetd.conf'.
-            See `gnunetd.conf(5)' for details.
+            List of network interfaces to use.
           '';
         };
       };
+
+      extraOptions = mkOption {
+        default = "";
+        example = ''
+          [NETWORK]
+          INTERFACE = eth3
+        '';
+        description = ''
+          Additional options that will be copied verbatim in `gnunetd.conf'.
+          See `gnunetd.conf(5)' for details.
+        '';
+      };
     };
+
   };
-in
 
-###### implementation
 
-mkIf config.services.gnunet.enable {
-  require = [
-    options
-  ];
+  ###### implementation
+
+  config = mkIf config.services.gnunet.enable {
 
-  users = {
-    extraUsers = [
+    users.extraUsers = singleton
       { name = "gnunetd";
         uid = config.ids.uids.gnunetd;
         description = "GNUnet Daemon User";
         home = "/var/empty";
-      }
-    ];
-  };
+      };
+
+    jobAttrs.gnunetd =
+      { description = "The GNUnet Daemon";
+
+        startOn = "network-interfaces/started";
+        stopOn = "network-interfaces/stop";
 
-  services = {
-    extraJobs = [{
-        name = "gnunetd";
-
-        job =
-          with config.services.gnunet;
-          let 
-            inherit (pkgs) lib gnunet;
-            configFile = pkgs.writeText "gnunetd.conf" ''
-              [PATHS]
-              GNUNETD_HOME = ${home}
-
-              [GNUNETD]
-              HOSTLISTURL = ${lib.concatStringsSep " " hostLists}
-              APPLICATIONS = ${lib.concatStringsSep " " applications}
-              TRANSPORTS = ${lib.concatStringsSep " " transports}
-
-              [LOAD]
-              MAXNETDOWNBPSTOTAL = ${toString load.maxNetDownBandwidth}
-              MAXNETUPBPSTOTAL = ${toString load.maxNetUpBandwidth}
-              HARDUPLIMIT = ${toString load.hardNetUpBandwidth}
-              MAXCPULOAD = ${toString load.maxCPULoad}
-              INTERFACES = ${lib.concatStringsSep " " load.interfaces}
-
-              [FS]
-              QUOTA = ${toString fileSharing.quota}
-              ACTIVEMIGRATION = ${if fileSharing.activeMigration then "YES" else "NO"}
-
-              [MODULES]
-              sqstore = sqstore_sqlite
-              dstore = dstore_sqlite
-              topology = topology_default
-
-              ${extraOptions}
-            '';
-            in ''
-            description "The GNUnet Daemon"
-
-            start on network-interfaces/started
-            stop on network-interfaces/stop
-
-            start script
-                test -d "${home}" || \
-                ( mkdir -m 755 -p "${home}" && chown -R gnunetd:users "${home}")
-            end script
-
-            respawn ${gnunet}/bin/gnunetd                   \
+        preStart =
+          ''
+            test -d "${cfg.home}" || \
+              ( mkdir -m 755 -p "${cfg.home}" && chown -R gnunetd:users "${cfg.home}")
+          '';
+
+        exec =
+          ''
+            respawn ${pkgs.gnunet}/bin/gnunetd              \
               ${if debug then "--debug" else "" }           \
               --user="gnunetd"                              \
               --config="${configFile}"                      \
-              --log="${logLevel}"
-            '';
-    }];
+              --log="${cfg.logLevel}"
+          '';
+      };
+
   };
+
 }
diff --git a/modules/services/networking/gw6c.nix b/modules/services/networking/gw6c.nix
index 502a7b1826e..961940d534a 100644
--- a/modules/services/networking/gw6c.nix
+++ b/modules/services/networking/gw6c.nix
@@ -1,141 +1,143 @@
-{servicesPath, pkgs, config, ...}:
+{ config, pkgs, servicesPath, ... }:
+
+with pkgs.lib;
 
-###### interface
 let
-  inherit (pkgs.lib) mkOption mkIf;
+
+  cfg = config.services.gw6c;
+
+  gw6cService = import (servicesPath + /gw6c) {
+    inherit (pkgs) stdenv gw6c coreutils 
+      procps upstart iputils gnused 
+      gnugrep seccure writeScript;
+    username = cfg.username;
+    password = cfg.password;
+    server = cfg.server;
+    keepAlive = cfg.keepAlive;
+    everPing = cfg.everPing;
+    seccureKeys = config.security.seccureKeys;
+    waitPingableBroker = cfg.waitPingableBroker;
+  };
+  
+in
+
+{
+
+  ###### interface
 
   options = {
-    services = {
-      gw6c = {
-        enable = mkOption {
-          default = false;
-          description = "
-            Whether to enable Gateway6 client (IPv6 tunnel).
-          ";
-        };
-
-        autorun = mkOption {
-          default = true;
-          description = "
-            Switch to false to create upstart-job and configuration, 
-            but not run it automatically
-          ";
-        };
-
-        username = mkOption {
-          default = "";
-          description = "
-            Your Gateway6 login name, if any.
-          ";
-        };
-
-        password = mkOption {
-          default = "";
-          description = "
-            Your Gateway6 password, if any.
-          ";
-        };
-
-        server = mkOption {
-          default = "anon.freenet6.net";
-          example = "broker.freenet6.net";
-          description = "
-            Used Gateway6 server.
-          ";
-        };
-
-        keepAlive = mkOption {
-          default = "30";
-          example = "2";
-          description = "
-            Gateway6 keep-alive period.
-          ";
-        };
-
-        everPing = mkOption {
-          default = "1000000";
-          example = "2";
-          description = "
-            Gateway6 manual ping period.
-          ";
-        };
-
-        waitPingableBroker = mkOption {
-          default = true;
-          example = false;
-          description = "
-            Whether to wait until tunnel broker returns ICMP echo.
-          ";
-        };
+  
+    services.gw6c = {
+    
+      enable = mkOption {
+        default = false;
+        description = "
+          Whether to enable Gateway6 client (IPv6 tunnel).
+        ";
       };
-    };
-    security = {
-      seccureKeys = {
-        public = mkOption {
-          default = /var/elliptic-keys/public;
-          description = "
-            Public key. Make it path argument, so it is copied into store and
-            hashed. 
-
-            The key is used to encrypt Gateway 6 configuration in store, as it
-            contains a password for external service. Unfortunately, 
-            derivation file should be protected by other means. For example, 
-            nix-http-export.cgi will happily export any non-derivation path,
-            but not a derivation.
-          ";
-        };
-
-        private = mkOption {
-          default = "/var/elliptic-keys/private";
-          description = "
-            Private key. Make it string argument, so it is not copied into store.
-          ";
-        };
+
+      autorun = mkOption {
+        default = true;
+        description = "
+          Switch to false to create upstart-job and configuration, 
+          but not run it automatically
+        ";
+      };
+
+      username = mkOption {
+        default = "";
+        description = "
+          Your Gateway6 login name, if any.
+        ";
+      };
+
+      password = mkOption {
+        default = "";
+        description = "
+          Your Gateway6 password, if any.
+        ";
+      };
+
+      server = mkOption {
+        default = "anon.freenet6.net";
+        example = "broker.freenet6.net";
+        description = "
+          Used Gateway6 server.
+        ";
+      };
+
+      keepAlive = mkOption {
+        default = "30";
+        example = "2";
+        description = "
+          Gateway6 keep-alive period.
+        ";
       };
+
+      everPing = mkOption {
+        default = "1000000";
+        example = "2";
+        description = "
+          Gateway6 manual ping period.
+        ";
+      };
+
+      waitPingableBroker = mkOption {
+        default = true;
+        example = false;
+        description = "
+          Whether to wait until tunnel broker returns ICMP echo.
+        ";
+      };
+
     };
-  };
-in
+    
+    security.seccureKeys = {
+
+      # !!! It's not clear to me (ED) what additional security this
+      # provides.  Passwords shouldn't be in configuration.nix,
+      # period.  You could just place the password in
+      # /var/blah/password or whatever.
+    
+      public = mkOption {
+        default = /var/elliptic-keys/public;
+        description = "
+          Public key. Make it path argument, so it is copied into store and
+          hashed. 
+
+          The key is used to encrypt Gateway 6 configuration in store, as it
+          contains a password for external service. Unfortunately, 
+          derivation file should be protected by other means. For example, 
+          nix-http-export.cgi will happily export any non-derivation path,
+          but not a derivation.
+        ";
+      };
 
-###### implementation
+      private = mkOption {
+        default = "/var/elliptic-keys/private";
+        description = "
+          Private key. Make it string argument, so it is not copied into store.
+        ";
+      };
 
-let
-        cfg = config.services.gw6c;
-        procps = pkgs.procps;
-        gw6cService = import (servicesPath + /gw6c) {
-                inherit (pkgs) stdenv gw6c coreutils 
-                procps upstart iputils gnused 
-                gnugrep seccure writeScript;
-                username = cfg.username;
-                password = cfg.password;
-                server = cfg.server;
-                keepAlive = cfg.keepAlive;
-                everPing = cfg.everPing;
-
-                seccureKeys = config.security.seccureKeys;
-
-                waitPingableBroker = cfg.waitPingableBroker;
-        };
-in
+    };
 
+  };
+  
+
+  ###### implementation
 
-mkIf config.services.gw6c.enable {
-  require = [
-    options
-  ];
+  config = mkIf cfg.enable {
 
-  services = {
-    extraJobs = [{
-        name = "gw6c";
-        users = [];
-        groups = [];
-        job = ''
-          description \"Gateway6 client\"
+    jobAttrs.gw6c =
+      { description = "Gateway6 client";
+      
+        startOn = if cfg.autorun then "network-interfaces/started" else "";
+        stopOn = "network-interfaces/stop";
 
-          start on ${ if cfg.autorun then "network-interfaces/started" else "never" }
-          stop on network-interfaces/stop
+        exec = "${gw6cService}/bin/control start";
+      };
 
-          respawn ${gw6cService}/bin/control start
-        '';
-    }];
   };
+
 }
diff --git a/modules/services/networking/ircd-hybrid.nix b/modules/services/networking/ircd-hybrid.nix
index 070abc1ef22..e59f9a8fa4f 100644
--- a/modules/services/networking/ircd-hybrid.nix
+++ b/modules/services/networking/ircd-hybrid.nix
@@ -1,89 +1,11 @@
-{servicesPath, pkgs, config, ...}:
+{ config, pkgs, servicesPath, ... }:
 
-###### interface
-let
-  inherit (pkgs.lib) mkOption mkIf;
-
-  options = {
-    services = {
-      ircdHybrid = {
-
-        enable = mkOption {
-          default = false;
-          description = "
-            Enable IRCD.
-          ";
-        };
-
-        serverName = mkOption {
-          default = "hades.arpa";
-          description = "
-            IRCD server name.
-          ";
-        };
-
-        sid = mkOption {
-          default = "0NL";
-          description = "
-            IRCD server unique ID in a net of servers.
-          ";
-        };
-
-        description = mkOption {
-          default = "Hybrid-7 IRC server.";
-          description = "
-            IRCD server description.
-          ";
-        };
-
-        rsaKey = mkOption {
-          default = null;
-          example = /root/certificates/irc.key;
-          description = "
-            IRCD server RSA key. 
-          ";
-        };
-
-        certificate = mkOption {
-          default = null;
-          example = /root/certificates/irc.pem;
-          description = "
-            IRCD server SSL certificate. There are some limitations - read manual.
-          ";
-        };
-
-        adminEmail = mkOption {
-          default = "<bit-bucket@example.com>";
-          example = "<name@domain.tld>";
-          description = "
-            IRCD server administrator e-mail. 
-          ";
-        };
-
-        extraIPs = mkOption {
-          default = [];
-          example = ["127.0.0.1"];
-          description = "
-            Extra IP's to bind.
-          ";
-        };
-
-        extraPort = mkOption {
-          default = "7117";
-          description = "
-            Extra port to avoid filtering.
-          ";
-        };
-
-      };
-    };
-  };
-in
-
-###### implementation
+with pkgs.lib;
 
 let
+
   cfg = config.services.ircdHybrid;
+  
   ircdService = import (servicesPath + /ircd-hybrid) {
     stdenv = pkgs.stdenv;
     inherit (pkgs) ircdHybrid coreutils 
@@ -96,35 +18,116 @@ let
     adminEmail = cfg.adminEmail;
     extraIPs = cfg.extraIPs;
     extraPort = cfg.extraPort;
-    gw6cEnabled = (config.services.gw6c.enable) &&
-            (config.services.gw6c.autorun);
+    gw6cEnabled = config.services.gw6c.enable && config.services.gw6c.autorun;
   };
 
   startingDependency = if config.services.gw6c.enable then "gw6c" else "network-interfaces";
 
 in
 
-mkIf config.services.ircdHybrid.enable {
-  require = [
-    options
-  ];
-
-  services = {
-    extraJobs = [{
-      name = "ircd-hybrid";
-      users = [ {
-                      name = "ircd"; 
-                      description = "IRCD owner.";
-              } ];
-      groups = [{name = "ircd";}];
-      job = ''
-        description = "IRCD Hybrid server."
-
-        start on ${startingDependency}/started
-        stop on ${startingDependency}/stop
-
-        respawn ${ircdService}/bin/control start
-      '';
-    }];
+{
+
+  ###### interface
+
+  options = {
+  
+    services.ircdHybrid = {
+
+      enable = mkOption {
+        default = false;
+        description = "
+          Enable IRCD.
+        ";
+      };
+
+      serverName = mkOption {
+        default = "hades.arpa";
+        description = "
+          IRCD server name.
+        ";
+      };
+
+      sid = mkOption {
+        default = "0NL";
+        description = "
+          IRCD server unique ID in a net of servers.
+        ";
+      };
+
+      description = mkOption {
+        default = "Hybrid-7 IRC server.";
+        description = "
+          IRCD server description.
+        ";
+      };
+
+      rsaKey = mkOption {
+        default = null;
+        example = /root/certificates/irc.key;
+        description = "
+          IRCD server RSA key. 
+        ";
+      };
+
+      certificate = mkOption {
+        default = null;
+        example = /root/certificates/irc.pem;
+        description = "
+          IRCD server SSL certificate. There are some limitations - read manual.
+        ";
+      };
+
+      adminEmail = mkOption {
+        default = "<bit-bucket@example.com>";
+        example = "<name@domain.tld>";
+        description = "
+          IRCD server administrator e-mail. 
+        ";
+      };
+
+      extraIPs = mkOption {
+        default = [];
+        example = ["127.0.0.1"];
+        description = "
+          Extra IP's to bind.
+        ";
+      };
+
+      extraPort = mkOption {
+        default = "7117";
+        description = "
+          Extra port to avoid filtering.
+        ";
+      };
+
+    };
+
   };
+
+
+  ###### implementation
+
+  config = mkIf config.services.ircdHybrid.enable {
+
+    users.extraUsers = singleton
+      { name = "ircd"; 
+        description = "IRCD owner";
+      };
+
+    users.extraGroups = singleton
+      { name = "ircd"; };
+
+    jobAttrs.ircd_hybrid =
+      { # name = "ircd-hybrid"; !!! mkIf bug
+
+        description = "IRCD Hybrid server";
+
+        startOn = "${startingDependency}/started";
+        stopOn = "${startingDependency}/stop";
+
+        exec = "${ircdService}/bin/control start";
+      };
+
+  };
+
 }
diff --git a/modules/services/networking/openfire.nix b/modules/services/networking/openfire.nix
index fa51ad173a3..e009498546c 100644
--- a/modules/services/networking/openfire.nix
+++ b/modules/services/networking/openfire.nix
@@ -1,65 +1,62 @@
-{pkgs, config, ...}:
+{ config, pkgs, ... }:
+
+with pkgs.lib;
 
-###### interface
 let
-  inherit (pkgs.lib) mkOption mkIf;
 
-  options = {
-    services = {
-      openfire = {
-        enable = mkOption {
-          default = false;
-          description = "
-            Whether to enable OpenFire XMPP server.
-          ";
-        };
-        usePostgreSQL = mkOption {
-          default = true;
-          description = "
-            Whether you use PostgreSQL service for your storage back-end.
-          ";
-        };
-      };
-    };
-  };
+  inherit (pkgs) jre openfire coreutils which gnugrep gawk gnused;
+    
+  startDependency =
+    if config.services.openfire.usePostgreSQL then "postgresql" else
+    if config.services.gw6c.enable then "gw6c" else
+    "network-interfaces";
+    
 in
 
-###### implementation
+{
 
-let
-  inherit (pkgs) jre openfire coreutils which gnugrep gawk gnused;
+  ###### interface
+
+  options = {
+  
+    services.openfire = {
     
-  startDependency = if config.services.openfire.usePostgreSQL then 
-    "postgresql"
-  else
-    if config.services.gw6c.enable then 
-      "gw6c" 
-    else 
-      "network-interfaces";
-in
+      enable = mkOption {
+        default = false;
+        description = "
+          Whether to enable OpenFire XMPP server.
+        ";
+      };
+      
+      usePostgreSQL = mkOption {
+        default = true;
+        description = "
+          Whether you use PostgreSQL service for your storage back-end.
+        ";
+      };
 
-mkIf config.services.openfire.enable {
+    };
 
-  assertions = [ {
-    assertion = !(config.services.openfire.usePostgreSQL -> config.services.postgresql.enable);
-    message = "openfire assertion failed";
-  } ];
+  };
 
-  require = [
-    options
-  ];
 
+  ###### implementation
 
-  services = {
-      extraJobs = [{
-        name = "openfire";
-        job = ''
-          description "OpenFire XMPP server"
+  config = mkIf config.services.openfire.enable {
 
-          start on ${startDependency}/started
-          stop on shutdown
+    assertions = singleton
+      { assertion = !(config.services.openfire.usePostgreSQL -> config.services.postgresql.enable);
+        message = "openfire assertion failed";
+      };
+
+    jobAttrs.openfire =
+      { description = "OpenFire XMPP server";
+
+        startOn = "${startDependency}/started";
+        stopOn = "shutdown";
 
-          script 
+        script =
+          ''
             export PATH=${jre}/bin:${openfire}/bin:${coreutils}/bin:${which}/bin:${gnugrep}/bin:${gawk}/bin:${gnused}/bin
             export HOME=/tmp
             mkdir /var/log/openfire || true 
@@ -70,8 +67,9 @@ mkIf config.services.openfire.enable {
                 fi
             done
             openfire start
-          end script
-        '';
-    }];
+          ''; # */
+      };
+
   };
+  
 }
diff --git a/modules/services/networking/openvpn.nix b/modules/services/networking/openvpn.nix
index 025a93d20a0..f7a8f51d9b1 100644
--- a/modules/services/networking/openvpn.nix
+++ b/modules/services/networking/openvpn.nix
@@ -1,83 +1,14 @@
+{ config, pkgs, ... }:
 
-{pkgs, config, ...}:
+with pkgs.lib;
 
-###### interface
 let
-  inherit (pkgs.lib) mkOption mkIf;
-
-  options = {
-    services = {
-      openvpn = {
-        enable = mkOption {
-          default = false;
-          description = "
-            Whether to enable the Secure Shell daemon, which allows secure
-            remote logins.
-          ";
-        };
-        servers = mkOption {
-          example = [
-            {
-              id = "server-simplest";
-              config = ''
-                # Most simple configuration: http://openvpn.net/index.php/documentation/miscellaneous/static-key-mini-howto.html.
-                # server : 
-                dev tun
-                ifconfig 10.8.0.1 10.8.0.2
-                secret static.key
-              '';
-              up = "ip route add ..!";
-              down = "ip route add ..!";
-            }
-            {
-              id = "client-simplest";
-              config = ''
-                #client:
-                #remote myremote.mydomain
-                #dev tun
-                #ifconfig 10.8.0.2 10.8.0.1
-                #secret static.key
-              '';
-            }
-            {
-              id = "server-scalable";
-              config = ''
-                multiple clienst
-                see example file found in http://openvpn.net/index.php/documentation/howto.html
-              '';
-            }
-            {
-              id = "client-scalabe";
-              config = '' dito '';
-            }
-          ];
-          default = [];
-          description = ''
-            openvpn instances to be run. Each will be put into an extra job named openvpn-{id}
-
-            The up and down properties will be added config line up=/nix/store/xxx-up-script
-            automatically for you. If you define at least one of up/down
-            "script-security 2" will be prepended to your config.
-
-            Don't forget to check that the all package sizes can be sent. if scp hangs or such you should set
-            --fragment XXX --mssfix YYY.
-          '';
-        };
-      };
-    };
-  };
-
-
-  modprobe = config.system.sbin.modprobe;
-
-###### implementation
 
   cfg = config.services.openvpn;
 
   inherit (pkgs) openvpn;
-  inherit (builtins) hasAttr;
 
-  PATH="${pkgs.iptables}/sbin:${pkgs.coreutils}/bin:${pkgs.iproute}/sbin:${pkgs.nettools}/sbin";
+  PATH = "${pkgs.iptables}/sbin:${pkgs.coreutils}/bin:${pkgs.iproute}/sbin:${pkgs.nettools}/sbin";
 
   makeOpenVPNJob = cfg :
     let
@@ -93,42 +24,105 @@ let
         PATH=${PATH}
         ${cfg.down}
       '';
-      configFile = pkgs.writeText "openvpn-config-${cfg.id}" ''
-      ${if hasAttr "up" cfg || hasAttr "down" cfg then "script-security 2" else ""}
-      ${cfg.config}
-      ${if hasAttr "up" cfg then "up ${pkgs.writeScript "openvpn-${cfg.id}-up" upScript}" else "" }
-      ${if hasAttr "down" cfg then "down ${pkgs.writeScript "openvpn-${cfg.id}-down" downScript}" else "" }
-      '';
+      configFile = pkgs.writeText "openvpn-config-${cfg.id}"
+        ''
+          ${if cfg ? up || cfg ? down then "script-security 2" else ""}
+          ${cfg.config}
+          ${if cfg ? up then "up ${pkgs.writeScript "openvpn-${cfg.id}-up" upScript}" else "" }
+          ${if cfg ? down then "down ${pkgs.writeScript "openvpn-${cfg.id}-down" downScript}" else "" }
+        '';
     in {
-      name = "openvpn-${cfg.id}";
-
-      job = ''
-        description "OpenVPN-${cfg.id}"
-
-        start on network-interfaces/started
-        stop on network-interfaces/stop
+      description = "OpenVPN-${cfg.id}";
 
+      startOn = "network-interfaces/started";
+      stopOn = "network-interfaces/stop";
 
-        PATH=${pkgs.coreutils}/bin
+      environment = { PATH = "${pkgs.coreutils}/bin"; };
 
-        respawn
-        script
+      script =
+        ''
           exec &> /var/log/openvpn-${cfg.id}
-          ${modprobe} tun || true
+          ${config.system.sbin.modprobe} tun || true
           ${openvpn}/sbin/openvpn --config ${configFile}
-        end script
-      '';
+        '';
     };
 
 in
+  
+{
+
+  ###### interface
+
+  options = {
+  
+    services.openvpn = {
+    
+      enable = mkOption {
+        default = false;
+        description = "Whether to enable OpenVPN.";
+      };
+
+      servers = mkOption {
+        example = [
+          {
+            id = "server-simplest";
+            config = ''
+              # Most simple configuration: http://openvpn.net/index.php/documentation/miscellaneous/static-key-mini-howto.html.
+              # server : 
+              dev tun
+              ifconfig 10.8.0.1 10.8.0.2
+              secret static.key
+            '';
+            up = "ip route add ..!";
+            down = "ip route add ..!";
+          }
+          {
+            id = "client-simplest";
+            config = ''
+              #client:
+              #remote myremote.mydomain
+              #dev tun
+              #ifconfig 10.8.0.2 10.8.0.1
+              #secret static.key
+            '';
+          }
+          {
+            id = "server-scalable";
+            config = ''
+              multiple clienst
+              see example file found in http://openvpn.net/index.php/documentation/howto.html
+            '';
+          }
+          {
+            id = "client-scalabe";
+            config = '' dito '';
+          }
+        ];
+        default = [];
+        # !!! clean up this description please
+        description = ''
+          openvpn instances to be run. Each will be put into an extra job named openvpn-{id}
+
+          The up and down properties will be added config line up=/nix/store/xxx-up-script
+          automatically for you. If you define at least one of up/down
+          "script-security 2" will be prepended to your config.
+
+          Don't forget to check that the all package sizes can be sent. if scp hangs or such you should set
+          --fragment XXX --mssfix YYY.
+        '';
+      };
+      
+    };
+
+  };
+
 
+  ###### implementation
 
-mkIf cfg.enable {
-  require = [
-    options
-  ];
+  config = mkIf cfg.enable {
 
-  services = {
-    extraJobs = map makeOpenVPNJob cfg.servers;
+    jobAttrs = listToAttrs (map (c: nameValuePair "openvpn-${cfg.id}" (makeOpenVPNJob c)) cfg.servers);
+  
   };
+  
 }
diff --git a/modules/services/networking/portmap.nix b/modules/services/networking/portmap.nix
index 5583108f894..08cd2457bcc 100644
--- a/modules/services/networking/portmap.nix
+++ b/modules/services/networking/portmap.nix
@@ -1,89 +1,84 @@
-{pkgs, config, ...}:
+{ config, pkgs, ... }:
+
+with pkgs.lib;
 
-###### interface
 let
-  inherit (pkgs.lib) mkOption mkIf;
 
-  options = {
-    services = {
-      portmap = {
-        enable = mkOption {
-          default = false;
-          description = ''
-            Whether to enable `portmap', an ONC RPC directory service
-            notably used by NFS and NIS, and which can be queried
-            using the rpcinfo(1) command.
-          '';
-        };
+  uid = config.ids.uids.portmap;
+  gid = config.ids.gids.portmap;
 
-        verbose = mkOption {
-          default = false;
-          description = ''
-            Whether to enable verbose output.
-          '';
-        };
+  portmap = pkgs.portmap.override { daemonUID = uid; daemonGID = gid; };
+  
+in
 
-        chroot = mkOption {
-          default = "/var/empty";
-          description = ''
-            If non-empty, a path to change root to.
-          '';
-        };
+{
 
+  ###### interface
+
+  options = {
+  
+    services.portmap = {
+    
+      enable = mkOption {
+        default = false;
+        description = ''
+          Whether to enable `portmap', an ONC RPC directory service
+          notably used by NFS and NIS, and which can be queried
+          using the rpcinfo(1) command.
+        '';
       };
-    };
-  };
-in
 
-###### implementation
+      verbose = mkOption {
+        default = false;
+        description = ''
+          Whether to enable verbose output.
+        '';
+      };
 
-let uid = config.ids.uids.portmap;
-    gid = config.ids.gids.portmap;
-in
+      chroot = mkOption {
+        default = "/var/empty";
+        description = ''
+          If non-empty, a path to change root to.
+        '';
+      };
 
-mkIf config.services.portmap.enable {
+    };
 
-  require = [
-    options
-  ];
+  };
+  
 
+  ###### implementation
 
-  users = {
-    extraUsers = [
+  config = mkIf config.services.portmap.enable {
+
+    users.extraUsers = singleton
       { name = "portmap";
         inherit uid;
         description = "portmap daemon user";
         home = "/var/empty";
-      }
-    ];
+      };
 
-    extraGroups = [
+    users.extraGroups = singleton
       { name = "portmap";
         inherit gid;
-      }
-    ];
-  };
+      };
 
-  services = {
-    extraJobs = [{ 
-      name = "portmap";
-      
+    jobAttrs.portmap =
+      { description = "ONC RPC portmap";
 
-      job =
-        let portmap = pkgs.portmap.override { daemonUID = uid; daemonGID = gid; };
-        in
-          ''
-          description "ONC RPC portmap"
+        startOn = "network-interfaces/started";
+        stopOn = "network-interfaces/stop";
 
-          start on network-interfaces/started
-          stop on network-interfaces/stop
+        exec =
+          ''
+            ${portmap}/sbin/portmap -f \
+              ${if config.services.portmap.chroot == ""
+                then ""
+                else "-t \"${config.services.portmap.chroot}\""} \
+              ${if config.services.portmap.verbose then "-v" else ""}
+          '';
+      };
 
-          respawn ${portmap}/sbin/portmap -f \
-            ${if config.services.portmap.chroot == ""
-              then ""
-              else "-t \"${config.services.portmap.chroot}\""} \
-            ${if config.services.portmap.verbose then "-v" else ""}
-        '';
-    }];
   };
+
 }
diff --git a/modules/services/networking/ssh/lshd.nix b/modules/services/networking/ssh/lshd.nix
index c6b529e66ee..35eaa0c743f 100644
--- a/modules/services/networking/ssh/lshd.nix
+++ b/modules/services/networking/ssh/lshd.nix
@@ -1,138 +1,132 @@
-{pkgs, config, ...}:
+{ config, pkgs, ... }:
 
-###### interface
-let
-  inherit (pkgs.lib) mkOption mkIf;
+with pkgs.lib;
+
+let 
+
+  inherit (pkgs) lsh;
+
+  cfg = config.services.lshd;
+
+in
+
+{
+
+  ###### interface
 
   options = {
-    services = {
-      lshd = {
-
-        enable = mkOption {
-          default = false;
-          description = ''
-            Whether to enable the GNU lshd SSH2 daemon, which allows
-            secure remote login.
-          '';
-        };
+  
+    services.lshd = {
+
+      enable = mkOption {
+        default = false;
+        description = ''
+          Whether to enable the GNU lshd SSH2 daemon, which allows
+          secure remote login.
+        '';
+      };
 
-        portNumber = mkOption {
-          default = 22;
-          description = ''
-            The port on which to listen for connections.
-          '';
-        };
-
-        interfaces = mkOption {
-          default = [];
-          description = ''
-            List of network interfaces where listening for connections.
-            When providing the empty list, `[]', lshd listens on all
-            network interfaces.
-          '';
-          example = [ "localhost" "1.2.3.4:443" ];
-        };
-
-        hostKey = mkOption {
-          default = "/etc/lsh/host-key";
-          description = ''
-            Path to the server's private key.  Note that this key must
-            have been created, e.g., using "lsh-keygen --server |
-            lsh-writekey --server", so that you can run lshd.
-          '';
-        };
-
-        syslog = mkOption {
-          default = true;
-          description = ''Whether to enable syslog output.'';
-        };
-
-        passwordAuthentication = mkOption {
-          default = true;
-          description = ''Whether to enable password authentication.'';
-        };
-
-        publicKeyAuthentication = mkOption {
-          default = true;
-          description = ''Whether to enable public key authentication.'';
-        };
-
-        rootLogin = mkOption {
-          default = false;
-          description = ''Whether to enable remote root login.'';
-        };
-
-        loginShell = mkOption {
-          default = null;
-          description = ''
-            If non-null, override the default login shell with the
-            specified value.
-          '';
-          example = "/nix/store/xyz-bash-10.0/bin/bash10";
-        };
+      portNumber = mkOption {
+        default = 22;
+        description = ''
+          The port on which to listen for connections.
+        '';
+      };
 
-        srpKeyExchange = mkOption {
-          default = false;
-          description = ''
-            Whether to enable SRP key exchange and user authentication.
-          '';
-        };
-
-        tcpForwarding = mkOption {
-          default = true;
-          description = ''Whether to enable TCP/IP forwarding.'';
-        };
-
-        x11Forwarding = mkOption {
-          default = true;
-          description = ''Whether to enable X11 forwarding.'';
-        };
-
-        subsystems = mkOption {
-          default = [ ["sftp" "${pkgs.lsh}/sbin/sftp-server"] ];
-          description = ''
-            List of subsystem-path pairs, where the head of the pair
-            denotes the subsystem name, and the tail denotes the path to
-            an executable implementing it.
-          '';
-        };
+      interfaces = mkOption {
+        default = [];
+        description = ''
+          List of network interfaces where listening for connections.
+          When providing the empty list, `[]', lshd listens on all
+          network interfaces.
+        '';
+        example = [ "localhost" "1.2.3.4:443" ];
       };
-    };
-  };
-in
 
-###### implementation
+      hostKey = mkOption {
+        default = "/etc/lsh/host-key";
+        description = ''
+          Path to the server's private key.  Note that this key must
+          have been created, e.g., using "lsh-keygen --server |
+          lsh-writekey --server", so that you can run lshd.
+        '';
+      };
 
-let 
+      syslog = mkOption {
+        default = true;
+        description = ''Whether to enable syslog output.'';
+      };
 
-  inherit (pkgs) lsh;
-  inherit (pkgs.lib) concatStrings concatStringsSep head tail;
+      passwordAuthentication = mkOption {
+        default = true;
+        description = ''Whether to enable password authentication.'';
+      };
 
-  lshdConfig = config.services.lshd;
+      publicKeyAuthentication = mkOption {
+        default = true;
+        description = ''Whether to enable public key authentication.'';
+      };
 
-  nssModules = config.system.nssModules.list;
+      rootLogin = mkOption {
+        default = false;
+        description = ''Whether to enable remote root login.'';
+      };
 
-  nssModulesPath = config.system.nssModules.path;
-in
+      loginShell = mkOption {
+        default = null;
+        description = ''
+          If non-null, override the default login shell with the
+          specified value.
+        '';
+        example = "/nix/store/xyz-bash-10.0/bin/bash10";
+      };
 
-mkIf config.services.lshd.enable {
-  require = [
-    options
-  ];
+      srpKeyExchange = mkOption {
+        default = false;
+        description = ''
+          Whether to enable SRP key exchange and user authentication.
+        '';
+      };
 
-  services = {
-    extraJobs = [{
-      name = "lshd";
+      tcpForwarding = mkOption {
+        default = true;
+        description = ''Whether to enable TCP/IP forwarding.'';
+      };
+
+      x11Forwarding = mkOption {
+        default = true;
+        description = ''Whether to enable X11 forwarding.'';
+      };
+
+      subsystems = mkOption {
+        default = [ ["sftp" "${pkgs.lsh}/sbin/sftp-server"] ];
+        description = ''
+          List of subsystem-path pairs, where the head of the pair
+          denotes the subsystem name, and the tail denotes the path to
+          an executable implementing it.
+        '';
+      };
       
-      job = with lshdConfig; ''
-        description "GNU lshd SSH2 daemon"
+    };
 
-        start on network-interfaces/started
-        stop on network-interfaces/stop
+  };
 
-        env LD_LIBRARY_PATH=${nssModulesPath}
 
-        start script
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    jobAttrs.lshd =
+      { description = "GNU lshd SSH2 daemon";
+
+        startOn = "network-interfaces/started";
+        stopOn = "network-interfaces/stop";
+
+        environment =
+          { LD_LIBRARY_PATH = config.system.nssModules.path; };
+
+        preStart =
+          ''
             test -d /etc/lsh || mkdir -m 0755 -p /etc/lsh
             test -d /var/spool/lsh || mkdir -m 0755 -p /var/spool/lsh
 
@@ -144,35 +138,37 @@ mkIf config.services.lshd.enable {
                 ${lsh}/bin/lsh-make-seed -o /var/spool/lsh/yarrow-seed-file
             fi
 
-            if ! test -f "${hostKey}"
+            if ! test -f "${cfg.hostKey}"
             then
                 ${lsh}/bin/lsh-keygen --server | \
-                ${lsh}/bin/lsh-writekey --server -o "${hostKey}"
+                ${lsh}/bin/lsh-writekey --server -o "${cfg.hostKey}"
             fi
-        end script
-
-        respawn ${lsh}/sbin/lshd --daemonic \
-           --password-helper="${lsh}/sbin/lsh-pam-checkpw" \
-           -p ${toString portNumber} \
-           ${if interfaces == [] then ""
-             else (concatStrings (map (i: "--interface=\"${i}\"")
-                                      interfaces))} \
-           -h "${hostKey}" \
-           ${if !syslog then "--no-syslog" else ""} \
-           ${if passwordAuthentication then "--password" else "--no-password" } \
-           ${if publicKeyAuthentication then "--publickey" else "--no-publickey" } \
-           ${if rootLogin then "--root-login" else "--no-root-login" } \
-           ${if loginShell != null then "--login-shell=\"${loginShell}\"" else "" } \
-           ${if srpKeyExchange then "--srp-keyexchange" else "--no-srp-keyexchange" } \
-           ${if !tcpForwarding then "--no-tcpip-forward" else "--tcpip-forward"} \
-           ${if x11Forwarding then "--x11-forward" else "--no-x11-forward" } \
-           --subsystems=${concatStringsSep ","
-                                           (map (pair: (head pair) + "=" +
-                                                       (head (tail pair)))
-                                                subsystems)}
-    '';
-  
-}
-    ];
+          '';
+
+        exec = with cfg;
+          ''
+            ${lsh}/sbin/lshd --daemonic \
+              --password-helper="${lsh}/sbin/lsh-pam-checkpw" \
+              -p ${toString portNumber} \
+              ${if interfaces == [] then ""
+                else (concatStrings (map (i: "--interface=\"${i}\"")
+                                         interfaces))} \
+              -h "${hostKey}" \
+              ${if !syslog then "--no-syslog" else ""} \
+              ${if passwordAuthentication then "--password" else "--no-password" } \
+              ${if publicKeyAuthentication then "--publickey" else "--no-publickey" } \
+              ${if rootLogin then "--root-login" else "--no-root-login" } \
+              ${if loginShell != null then "--login-shell=\"${loginShell}\"" else "" } \
+              ${if srpKeyExchange then "--srp-keyexchange" else "--no-srp-keyexchange" } \
+              ${if !tcpForwarding then "--no-tcpip-forward" else "--tcpip-forward"} \
+              ${if x11Forwarding then "--x11-forward" else "--no-x11-forward" } \
+              --subsystems=${concatStringsSep ","
+                                              (map (pair: (head pair) + "=" +
+                                                          (head (tail pair)))
+                                                   subsystems)}
+          '';
+      };
+         
   };
+  
 }
diff --git a/modules/services/networking/vsftpd.nix b/modules/services/networking/vsftpd.nix
index a0630de77cc..2a567f3ec90 100644
--- a/modules/services/networking/vsftpd.nix
+++ b/modules/services/networking/vsftpd.nix
@@ -1,160 +1,135 @@
-{pkgs, config, ...}:
+{ config, pkgs, ... }:
 
-###### interface
-let
-  inherit (pkgs.lib) mkOption mkIf;
+with pkgs.lib;
 
-  options = {
-    services = {
-      vsftpd = {
-        enable = mkOption {
-          default = false;
-          description = "
-            Whether to enable the vsftpd FTP server.
-          ";
-        };
-        
-        anonymousUser = mkOption {
-          default = false;
-          description = "
-            Whether to enable the anonymous FTP user.
-          ";
-        };
- 
-        anonymousUserHome = mkOption {
-          default = "/home/ftp";
-          description = "
-            Path to anonymous user data.
-          ";
-        };
- 
-        localUsers = mkOption {
-          default = false;
-          description = "
-            Whether to enable FTP for the local users.
-          ";
-        };
+let 
 
-        writeEnable = mkOption {
-          default = false;
-          description = "
-            Whether any write activity is permitted to users.
-          ";
-        };
+  cfg = config.services.vsftpd;
+  
+  inherit (pkgs) vsftpd;
 
-        anonymousUploadEnable = mkOption {
-          default = false;
-          description = "
-            Whether any uploads are permitted to anonymous users.
-          ";
-        };
+  yesNoOption = p : name :
+    "${name}=${if p then "YES" else "NO"}";
 
-        anonymousMkdirEnable = mkOption {
-          default = false;
-          description = "
-            Whether mkdir is permitted to anonymous users.
-          ";
-        };
+in
 
-        chrootlocalUser = mkOption {
-          default = false;
-          description = "
-            Whether u can like out of ur home dir.
-          ";
-        };
-  
-        userlistEnable  = mkOption {
-          default = false;
-          description = "
-            Whether users are included.
-          ";
-        };
+{
+
+  ###### interface
+
+  options = {
   
-        userlistDeny  = mkOption {
-          default = false;
-          description = "
-            Whether users are excluded.
-          ";
-        };
+    services.vsftpd = {
+    
+      enable = mkOption {
+        default = false;
+        description = "Whether to enable the vsftpd FTP server.";
       };
-    };
-  };
-in
 
-###### implementation
+      anonymousUser = mkOption {
+        default = false;
+        description = "Whether to enable the anonymous FTP user.";
+      };
 
-let 
+      anonymousUserHome = mkOption {
+        default = "/home/ftp";
+        description = "Path to anonymous user data.";
+      };
 
-  inherit (config.services.vsftpd) anonymousUser anonymousUserHome localUsers writeEnable anonymousUploadEnable anonymousMkdirEnable
-    chrootlocalUser userlistEnable userlistDeny;
-  inherit (pkgs) vsftpd;
+      localUsers = mkOption {
+        default = false;
+        description = "Whether to enable FTP for local users.";
+      };
 
-  yesNoOption = p : name :
-    "${name}=${if p then "YES" else "NO"}";
+      writeEnable = mkOption {
+        default = false;
+        description = "Whether any write activity is permitted to users.";
+      };
 
-in
+      anonymousUploadEnable = mkOption {
+        default = false;
+        description = "Whether any uploads are permitted to anonymous users.";
+      };
+
+      anonymousMkdirEnable = mkOption {
+        default = false;
+        description = "Whether mkdir is permitted to anonymous users.";
+      };
+
+      chrootlocalUser = mkOption {
+        default = false;
+        description = "Whether local users are confined to their home directory.";
+      };
+
+      userlistEnable = mkOption {
+        default = false;
+        description = "Whether users are included.";
+      };
+
+      userlistDeny = mkOption {
+        default = false;
+        description = "Whether users are excluded.";
+      };
+
+    };
+    
+  };
+  
 
-mkIf config.services.vsftpd.enable {
-  require = [
-    options
-  ];
+  ###### implementation
 
-  users = {
-    extraUsers = [
-        { name = "vsftpd";
+  config = mkIf cfg.enable {
+
+    users.extraUsers =
+      [ { name = "vsftpd";
           uid = config.ids.uids.vsftpd;
           description = "VSFTPD user";
           home = "/homeless-shelter";
         }
-      ] ++ pkgs.lib.optional anonymousUser
+      ] ++ pkgs.lib.optional cfg.anonymousUser
         { name = "ftp";
           uid = config.ids.uids.ftp;
           group = "ftp";
-          description = "Anonymous ftp user";
-          home = anonymousUserHome;
+          description = "Anonymous FTP user";
+          home = cfg.anonymousUserHome;
         };
 
-    extraGroups = [
+    users.extraGroups = singleton
       { name = "ftp";
         gid = config.ids.gids.ftp;
-      }
-    ];
-      
-  };
+      };
+
+    jobAttrs.vsftpd =
+      { description = "vsftpd server";
+
+        startOn = "network-interfaces/started";
+        stopOn = "network-interfaces/stop";
+
+        preStart =
+          ''
+            # !!! Why isn't this generated in the normal way?
+            cat > /etc/vsftpd.conf <<EOF
+            ${yesNoOption cfg.anonymousUser "anonymous_enable"}
+            ${yesNoOption cfg.localUsers "local_enable"}
+            ${yesNoOption cfg.writeEnable "write_enable"}
+            ${yesNoOption cfg.anonymousUploadEnable "anon_upload_enable"}
+            ${yesNoOption cfg.anonymousMkdirEnable "anon_mkdir_write_enable"}
+            ${yesNoOption cfg.chrootlocalUser "chroot_local_user"}
+            ${yesNoOption cfg.userlistEnable "userlist_enable"}
+            ${yesNoOption cfg.userlistDeny "userlist_deny"}
+            background=NO
+            listen=YES
+            nopriv_user=vsftpd
+            secure_chroot_dir=/var/ftp/empty
+            EOF
+
+            mkdir -p ${cfg.anonymousUserHome}
+            chown -R ftp:ftp ${cfg.anonymousUserHome}
+          '';
+
+        exec = "${vsftpd}/sbin/vsftpd /etc/vsftpd.conf";
+      };
 
-  services = {
-    extraJobs = [{
-      name = "vsftpd";
-
-      job = ''
-        description "vsftpd server"
-
-        start on network-interfaces/started
-        stop on network-interfaces/stop
-
-        start script
-        cat > /etc/vsftpd.conf <<EOF
-        ${yesNoOption anonymousUser "anonymous_enable"}
-        ${yesNoOption localUsers "local_enable"}
-        ${yesNoOption writeEnable "write_enable"}
-        ${yesNoOption anonymousUploadEnable "anon_upload_enable"}
-        ${yesNoOption anonymousMkdirEnable "anon_mkdir_write_enable"}
-        ${yesNoOption chrootlocalUser "chroot_local_user"}
-        ${yesNoOption userlistEnable "userlist_enable"}
-        ${yesNoOption userlistDeny "userlist_deny"}
-        background=NO
-        listen=YES
-        nopriv_user=vsftpd
-        secure_chroot_dir=/var/ftp/empty
-        EOF
-
-        mkdir -p ${anonymousUserHome} &&
-        chown -R ftp:ftp ${anonymousUserHome}
-        end script
-
-        respawn ${vsftpd}/sbin/vsftpd /etc/vsftpd.conf
-      '';
-      
-    }];
   };
+  
 }