Author: NicolasPierron
Date: Tue Nov 29 06:08:55 2011
New Revision: 30611
URL: https://nixos.org/websvn/nix/?rev=30611&sc=1

Log:
Convert users.extraUsers to an option set and add support for openssh
authorized_keys file generation.

Modified:
   nixos/trunk/modules/config/users-groups.nix
   nixos/trunk/modules/services/networking/ssh/sshd.nix

Modified: nixos/trunk/modules/config/users-groups.nix
==============================================================================
--- nixos/trunk/modules/config/users-groups.nix Tue Nov 29 05:13:20 2011        
(r30610)
+++ nixos/trunk/modules/config/users-groups.nix Tue Nov 29 06:08:55 2011        
(r30611)
@@ -5,43 +5,83 @@
 let
 
   ids = config.ids;
+  users = config.users;
 
+  userOpts = {name, config, ...}:
 
-  # User accounts to be created/updated by NixOS.
-  users =
-    let
-      defaultUsers =
-        [ { name = "root";
-            uid = ids.uids.root;
-            description = "System administrator";
-            home = "/root";
-            shell = config.users.defaultUserShell;
-            group = "root";
-          }
-          { name = "nobody";
-            uid = ids.uids.nobody;
-            description = "Unprivileged account (don't use!)";
-          }
-        ];
-
-      # !!! Use NixOS module system to add default attributes.
-      addAttrs =
-        { name
-        , description
-        , uid ? ""
-        , group ? "nogroup"
-        , extraGroups ? []
-        , home ? "/var/empty"
-        , shell ? (if useDefaultShell then config.users.defaultUserShell else 
"/noshell")
-        , createHome ? false
-        , useDefaultShell ? false
-        , password ? null
-        , isSystemUser ? true
-        }:
-        { inherit name description uid group extraGroups home shell createHome 
password isSystemUser; };
-
-    in map addAttrs (defaultUsers ++ config.users.extraUsers);
+  {
+    options = {
+      name = mkOption {
+        type = with types; uniq string;
+        description = "The name of the user account. If undefined, the name of 
the attribute set will be used.";
+      };
+      description = mkOption {
+        type = with types; uniq string;
+        default = "";
+        description = "A short description of the user account.";
+      };
+      uid = mkOption {
+        type = with types; uniq (nullOr int);
+        default = null;
+        description = "The account UID. If undefined, NixOS will select a 
UID.";
+      };
+      group = mkOption {
+        type = with types; uniq string;
+        default = "nogroup";
+        description = "The user's primary group.";
+      };
+      extraGroups = mkOption {
+        type = types.listOf types.string;
+        default = [];
+        description = "The user's auxiliary groups.";
+      };
+      home = mkOption {
+        type = with types; uniq string;
+        default = "/var/empty";
+        description = "The user's home directory.";
+      };
+      shell = mkOption {
+        type = with types; uniq string;
+        default = "/noshell";
+        description = "The path to the user's shell.";
+      };
+      createHome = mkOption {
+        type = types.bool;
+        default = false;
+        description = "If true, the home directory will be created 
automatically.";
+      };
+      useDefaultShell = mkOption {
+        type = types.bool;
+        default = false;
+        description = "If true, the user's shell will be set to 
<literal>users.defaultUserShell</literal>.";
+      };
+      password = mkOption {
+        type = with types; uniq (nullOr string);
+        default = null;
+        description = "The user's password. If undefined, no password is set 
for the user.  Warning: do not set confidential information here because this 
data would be readable by all.  This option should only be used for public 
account such as guest.";
+      };
+      isSystemUser = mkOption {
+        type = types.bool;
+        default = true;
+        description = "Indicates if the user is a system user or not.";
+      };
+      createUser = mkOption {
+        type = types.bool;
+        default = true;
+        description = "
+          Indicates if the user should be created automatically as a local 
user.
+          Set this to false if the user for instance is an LDAP user. NixOS 
will
+          then not modify any of the basic properties for the user account.
+        ";
+      };
+    };
 
+    config = {
+      name = mkDefault name;
+      uid = mkDefault (attrByPath [name] null ids.uids);
+      shell = mkIf config.useDefaultShell (mkDefault users.defaultUserShell);
+    };
+  };
 
   # Groups to be created/updated by NixOS.
   groups =
@@ -109,11 +149,14 @@
 
   # Note: the 'X' in front of the password is to distinguish between
   # having an empty password, and not having a password.
-  serializedUser = u: "${u.name}\n${u.description}\n${toString 
u.uid}\n${u.group}\n${toString (concatStringsSep "," 
u.extraGroups)}\n${u.home}\n${u.shell}\n${toString u.createHome}\n${if 
u.password != null then "X" + u.password else ""}\n${toString 
u.isSystemUser}\n";
+  serializedUser = userName: let u = getAttr userName config.users.extraUsers; 
in "${u.name}\n${u.description}\n${if u.uid != null then toString u.uid else 
""}\n${u.group}\n${toString (concatStringsSep "," 
u.extraGroups)}\n${u.home}\n${u.shell}\n${toString u.createHome}\n${if 
u.password != null then "X" + u.password else ""}\n${toString 
u.isSystemUser}\n${if u.createUser then "yes" else "no"}\n";
+
   serializedGroup = g: "${g.name}\n${toString g.gid}";
 
   # keep this extra file so that cat can be used to pass special chars such as 
"`" which is used in the avahi daemon
-  usersFile = pkgs.writeText "users" (concatStrings (map serializedUser 
users));
+  usersFile = pkgs.writeText "users" (
+    concatMapStrings serializedUser (attrNames config.users.extraUsers)
+  );
 
 in
 
@@ -124,22 +167,24 @@
   options = {
 
     users.extraUsers = mkOption {
-      default = [];
-      example =
-        [ { name = "alice";
-            uid = 1234;
-            description = "Alice";
-            home = "/home/alice";
-            createHome = true;
-            group = "users";
-            extraGroups = ["wheel"];
-            shell = "/bin/sh";
-            password = "foobar";
-          }
-        ];
+      default = {};
+      type = types.loaOf types.optionSet;
+      example = {
+        alice = {
+          uid = 1234;
+          description = "Alice";
+          home = "/home/alice";
+          createHome = true;
+          group = "users";
+          extraGroups = ["wheel"];
+          shell = "/bin/sh";
+          password = "foobar";
+        };
+      };
       description = ''
         Additional user accounts to be created automatically by the system.
       '';
+      options = [ userOpts ];
     };
 
     users.extraGroups = mkOption {
@@ -154,6 +199,15 @@
       '';
     };
 
+    user = mkOption {
+      default = {};
+      description = ''
+        This option defines settings for individual users on the system.
+      '';
+      type = types.loaOf types.optionSet;
+      options = [ ];
+    };
+
   };
 
 
@@ -161,6 +215,18 @@
 
   config = {
 
+    users.extraUsers = {
+      root = {
+        description = "System administrator";
+        home = "/root";
+        shell = config.users.defaultUserShell;
+        group = "root";
+      };
+      nobody = {
+        description = "Unprivileged account (don't use!)";
+      };
+    };
+
     system.activationScripts.rootPasswd = stringAfter [ "etc" ]
       ''
         # If there is no password file yet, create a root account with an
@@ -192,6 +258,11 @@
             read createHome
             read password
             read isSystemUser
+            read createUser
+
+            if ! test "$createUser" = "yes"; then
+                continue
+            fi
 
             if ! curEnt=$(getent passwd "$name"); then
                 useradd ''${isSystemUser:+--system} \

Modified: nixos/trunk/modules/services/networking/ssh/sshd.nix
==============================================================================
--- nixos/trunk/modules/services/networking/ssh/sshd.nix        Tue Nov 29 
05:13:20 2011        (r30610)
+++ nixos/trunk/modules/services/networking/ssh/sshd.nix        Tue Nov 29 
06:08:55 2011        (r30611)
@@ -14,6 +14,98 @@
     v == "forced-commands-only" ||
     v == "no";
 
+  userOptions = {
+    openssh.authorizedKeys = {
+
+      preserveExistingKeys = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          If this option is enabled, the keys specified in
+          <literal>keys</literal> and/or <literal>keyFiles</literal> will be
+          placed in a special section of the user's authorized_keys file
+          and any existing keys will be preserved. That section will be
+          regenerated each time NixOS is activated. However, if
+          <literal>preserveExisting</literal> isn't enabled, the complete file
+          will be generated, and any user modifications will be wiped out.
+        '';
+      };
+
+      keys = mkOption {
+        type = types.listOf types.string;
+        default = [];
+        description = ''
+          A list of verbatim OpenSSH public keys that should be inserted into 
the
+          user's authorized_keys file. You can combine the 
<literal>keys</literal> and
+          <literal>keyFiles</literal> options.
+        '';
+      };
+
+      keyFiles = mkOption {
+        type = types.listOf types.string;
+        default = [];
+        description = ''
+          A list of files each containing one OpenSSH public keys that should 
be
+          inserted into the user's authorized_keys file. You can combine
+          the <literal>keyFiles</literal> and
+          <literal>keys</literal> options.
+        '';
+      };
+
+    };
+  };
+
+  mkAuthkeyScript =
+    let
+      marker1 = "### NixOS will regenerate this line and every line below it.";
+      marker2 = "### NixOS will regenerate this file. Do not edit!";
+      users = map (userName: getAttr userName config.users.extraUsers) 
(attrNames config.users.extraUsers);
+      usersWithKeys = flip filter users (u:
+        length u.openssh.authorizedKeys.keys != 0 || length 
u.openssh.authorizedKeys.keyFiles != 0
+      );
+      userLoop = flip concatMapStrings usersWithKeys (u:
+        let
+          authKeys = concatStringsSep "," u.openssh.authorizedKeys.keys;
+          authKeyFiles = concatStringsSep "," 
u.openssh.authorizedKeys.keyFiles;
+          preserveExisting = if u.openssh.authorizedKeys.preserveExistingKeys 
then "true" else "false";
+        in ''
+          mkAuthKeysFile "${u.name}" "${authKeys}" "${authKeyFiles}" 
"${preserveExisting}"
+        ''
+      );
+    in ''
+      mkAuthKeysFile() {
+        local userName="$1"
+        local authKeys="$2"
+        local authKeyFiles="$3"
+        local preserveExisting="$4"
+        IFS=","
+
+        for f in $authKeyFiles; do
+          if [ -f "$f" ]; then
+            authKeys="$(${pkgs.coreutils}/bin/cat "$f"),$authKeys"
+          fi
+        done
+
+        if [ -n "$authKeys" ]; then
+          eval authfile=~$userName/.ssh/authorized_keys
+          ${pkgs.coreutils}/bin/mkdir -p "$(dirname $authfile)"
+          ${pkgs.coreutils}/bin/touch "$authfile"
+          if [ "$preserveExisting" == "false" ]; then
+            rm -f "$authfile"
+            authKeys="${marker2},$authKeys"
+          else
+            ${pkgs.gnused}/bin/sed -i '/^### NixOS.*$/,$d' "$authfile"
+            authKeys="${marker1},$authKeys"
+          fi
+          for key in $authKeys; do ${pkgs.coreutils}/bin/echo "$key" >> 
"$authfile"; done
+        fi
+
+        unset IFS
+      }
+      ${userLoop}
+    '';
+
+
 in
 
 {
@@ -102,6 +194,10 @@
 
     };
 
+    users.extraUsers = mkOption {
+      options = [ userOptions ];
+    };
+
   };
 
 
@@ -135,6 +231,8 @@
 
         preStart =
           ''
+            ${mkAuthkeyScript}
+
             mkdir -m 0755 -p /etc/ssh
 
             if ! test -f /etc/ssh/ssh_host_dsa_key; then
_______________________________________________
nix-commits mailing list
[email protected]
http://lists.science.uu.nl/mailman/listinfo/nix-commits

Reply via email to