NixOS / nixpkgs

Nix Packages collection & NixOS
MIT License
17.98k stars 13.99k forks source link

Documentation: users.users password options are incorrect about which options override which #269791

Open SquircleSpace opened 11 months ago

SquircleSpace commented 11 months ago

Problem

The latest documentation claims that

hashedPassword overrides both password and hashedPasswordFile. password overrides hashedPasswordFile

I find that the actual priority order is

  1. hashedPasswordFile
  2. password
  3. hashedPassword

As proof, I have attached a simple flake that defines 2 NixOS configurations: example1 and example2. In example1, I define a system that sets password and hashedPassword. The hashed password corresponds to the password "b". In example2, I additionally set hashedPasswordFile to a file containing the hashed representation of the password "c".

proof.tar.gz

If you boot up example1 in a vm, you'll find that you need to enter "a" to login. Thus, password overrides hashedPassword. If you boot up example2 in a vm, you'll find that you need to enter "c" to login. Thus, hashedPasswordFile overrides password and hashedPassword.

Interestingly, this means the actual behavior is the exact opposite of what the documentation describes!

Out of curiosity, I dug through the commit history for the script that generates /etc/shadow, and it seems like this documentation issues has been present since hashedPassword was introduced as an option. From the introduction of hashedPassword, the script that generates /etc/shadow has always preferred passwordFile and password over hashedPassword. This is easy to see in the current implementation:

https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/config/update-users-groups.pl#L242

    if (defined $u->{hashedPasswordFile}) {
        if (-e $u->{hashedPasswordFile}) {
            $u->{hashedPassword} = read_file($u->{hashedPasswordFile});
            chomp $u->{hashedPassword};
        } else {
            warn "warning: password file ‘$u->{hashedPasswordFile}’ does not exist\n";
        }
    } elsif (defined $u->{password}) {
        $u->{hashedPassword} = hashPassword($u->{password});
    }

This logic runs regardless of whether hashedPassword has been set. As a result, both hashedPasswordFile and password override hashedPassword

Proposal

The documentation should report the actual behavior of the code. The behavior should not be changed. We only need to change the wording slightly.

hashedPasswordFile overrides both password and hashedPassword. password overrides hashedPassword.

Checklist

Priorities

Add a :+1: reaction to issues you find important.

SquircleSpace commented 11 months ago

I discovered this because I am looking at doing something in my personal NixOS configuration that depends on the current behavior (not the documented behavior!).