Shell How to enter ENTER key in a script

What does your question even mean? What does "ENTER key" mean in this context? I can write a little program that displays a high resolution image of the enter key on the screen, but I don't think that's what you want. I think you're after printing a newline (or carriage return or some combination).

One way to print a single newline to the screen is to simply use the echo command with no parameters.

It is possible to create a string that contains a newline or a carriage return character (or more than one, or other control characters). Those strings can be piped into programs, or displayed on the screen. Doing so usually requires understanding the quoting rules in use by the shell.
 
The 'ENTER' key means that big key at the right side of your keyboard which you press after you have written an instruction at the command prompt and you want to execute it. I can't imagine there is any other way to interpret that.

What I'm getting at is if you run passwd and press ENTER, twice, then you have entered a valid password. If you don't do this you don't have a password. The difference is manifested when running sshd() on a system which doesn't have a password, you can't login, whereas you can do so using a blank password.

The reason for the question is, I can't figure out how to create a blank password from a script. Maybe a newline in a heredoc would suffice, but haven't managed to get that to work yet.

I'm trying to get this to work

Bash:
pw usermod -n root -h 0 << 'EOT'
[ENTER]                               
EOT

Using an empty line does not work, neither does '\n', although I probably have the quotes wrong.
 
pw mod user <user> -w none
pw()
[-h]
Alternatively, pw will prompt for the user's pass-
word if -h 0 is given, nominating stdin as the file de-
scriptor on which to read the password. Note that this
password will be read only once and is intended for use
by a script rather than for interactive use. If you wish
to have new password confirmation along the lines of
passwd(1), this must be implemented as part of an inter-
active script that calls pw.
printf()
printf "\r\n"

 
AFAIK you can provide own hash of given password when creating/changing user. So take one from passwd file where your root already has what you want and try that?
 
The 'ENTER' key means that big key at the right side of your keyboard
This is completely pointless, and I assume you already guessed that? :-/

The concept of a "key" only makes sense for interactive use, for example using some raw terminal mode, where the application can indeed receive "keys pressed". To script that, you'd actually have to "simulate" pressing the key somehow and run the original interactive program, including any side effects (like e.g. being visible). So, this doesn't make much sense, you should instead deal with the standard (text) input and output streams, and there's naturally no notion of any keys but just characters.

For your concrete issue, providing an empty string to standard input can easily be achieved by redirecting from /dev/null, e.g. here pw usermod -n root -h 0 </dev/null. That isn't your issue, your issue is that pw(8) just refuses to set an empty password with this method. How to do that instead was already shown by CuatroTorres.

All in all, your question was another example of the "XY-problem". Please, always at least provide necessary context to your assumed solution.

Having said all that, IMHO empty passwords are a very bad idea. They will also be rejected in many places (e.g. some PAM modules). If your ultimate goal is not having to type anything when using ssh, just use key-based authentication and add your private key to ssh-agent(1).
 
To disable password-based authentication (i. e. other mechanisms may still grant access):​
Bash:
pw usermod -n myuser -h -
To set a zero-length password (i. e. just typing the username is sufficient for login, there is no password prompt):​
Bash:
pw usermod -n myuser -w none
General-purpose scripted interaction: lang/expect (for future projects; it has a expect_passmass(1) tool you might be interested in).​
 
pw mod user <user> -w none
pw()

printf()
printf "\r\n"



pw mod user <user> -w none
Whilst that looks like the thing I want, it doesn't seem to work, although I will test it again.

It may be due to how you interpret

none force a blank password

Does 'blank password' mean no password? You can login to sshd if you set passwd ENTER ENTER. If you set pw to none it appears that password is not set at all, so you can't login.

I have just entered a blank password using passwd on my remote system and logged in via ssh, where I entered

pw usermod -n root -w none

then exited, but was unable to log back in.
 
To disable password-based authentication (i. e. other mechanisms may still grant access):​
Bash:
pw usermod -n myuser -h -
To set a zero-length password (i. e. just typing the username is sufficient for login, there is no password prompt):​
Bash:
pw usermod -n myuser -w none
General-purpose scripted interaction: lang/expect (for future projects).​
If you just use ENTER as a password you do get a password prompt. Not sure if that counts as zero length... probably not.
 
Does 'blank password' mean no password?
No. A blank or empty password is still a password (of length zero), which is exactly what the -w none option of pw(8) will set. No password at all means password authentication for that account isn't possible.

You can login to sshd if you set passwd ENTER ENTER.
Once again, a key is not a character and certainly can't be part of a password. passwd(1) implements a hidden prompt to interactively enter a password, using the ENTER key to finish input. Just hitting ENTER sets an empty password.

But checking all of this myself now: I assume you hit a glitch in passwd(1). It does something it probably should not do: It actually hashes the empty string and stores that hash in the password database. This makes little sense, an empty password should instead be stored as an empty hash, which allows to immediately recognize the fact that it is empty (and pw(8) does this correctly). As I already mentioned, empty passwords are rejected in many places. SSH (at least in the default configuration) is one of these places, empty passwords are forbidden there by default. Now if you have a hash, this seems to "trick" SSH into accepting it anyways. Might be worth a PR.

Bottom line IMHO still: don't use empty passwords. There are better ways to achieve what you want.
 
Definitively as this does not work as intended. Please open the PR as you found the bug.
Maybe users also should check if they have such an empty hash in use with SSH.
It could be debatable. I just checked the passwd source, it doesn't even handle the password database but leaves it all to pam_unix(8) instead.

There I found an IMHO better wording. Instead of "empty password", what I would expect (empty hash) is called "null password". This is still different from "disabled password" (which would mean something invalid as the password hash, by convention just an asterisk).

So, there is room for some "empty password" that does have a hash. I still think this shouldn't be done. Some others seem to agree, e.g. openssl-passwd(1) refuses to create an sha512 hash for an empty string ... and also, pam_unix(8) knows the option nullok to control whether these "null passwords" are accepted or not.

Anyways, if this is a bug, it's not in passwd(1) but somewhere in pam_unix(8). I'll certainly investigate further before reporting it, I prefer fully understanding the issue first.
 
I'll certainly investigate further before reporting it, I prefer fully understanding the issue first.
Great! AFAIK a "null password" can be an exploitable security hole and should not be found anywhere.
What happens if a "valid" hash gets replaced by a "null password" hash?
 
It could be debatable. I just checked the passwd source, it doesn't even handle the password database but leaves it all to pam_unix(8) instead.

There I found an IMHO better wording. Instead of "empty password", what I would expect (empty hash) is called "null password". This is still different from "disabled password" (which would mean something invalid as the password hash, by convention just an asterisk).

I prefer to call it a 'null password'. When you just copy base+kernel to a partition and boot up, you are presented with a login prompt but no password prompt. That is because the password has not yet been set, so I'm not sure what constitutes an 'empty password'.

As far as sshd() is concerned...

PermitEmptyPasswords
When password authentication is allowed, it specifies whether
the server allows login to accounts with empty password
strings. The default is no.

I have never figured out what this checks for....
 
check the adduser(8) with option -f to import users from file with the format name:uid:gid:class:change:expire:gecos:home_dir:shell:password

Code:
password     User password.     This field should contain a plaintext string,
         which will be encrypted before    being placed in    the user data-
         base.     If  the password type is yes and this field is    empty,
         it is assumed the account will    have an     empty    password.   If
         the  password type is random and this field is    not empty, its
         contents will be used as a password.  This field will be  ig-
         nored    if  the     -w option is used with    a no or    none argument.
         Be careful not    to terminate this field    with a closing `:' be-
         cause it will be treated as part of the password.
 
It's easy to cause massive confusion when talking about terms without a common definition in mind 🤪 – so here's an attempt to sort that out.

First a bit of background. In Unix systems, there's the classic passwd(5) database holding the local user accounts. One of the fields is the password field, holding the hashed password of the user. And then, there's PAM (pluggable authentication modules), which basically allows to use any other source for the user database instead of the local files, like e.g. some central LDAP directory, and also implement any kind of authentication mechanism instead of the simple username-password scheme. The PAM module accessing the local passwd(5) database is pam_unix(8). Lots of tools only use PAM to authenticate and manage users, like login(1), passwd(1), su(1), etc, so they can transparently use whatever is configured in /etc/pam.d. There are also tools dedicated to managing the local passwd(5) database directly, like pw(8). Some software can both use PAM as well as the local database directly, e.g. ssh.

So, talking about the traditional local database now, apart from just a "normal" hashed password, it's possible to store two "edge cases":
  • no (or: invalid) password. In this case, the field for the password hash holds something that is not a valid hash, by convention a single asterisk. As a consequence, password authentication for that user is disabled, no matter what (while it can still be possible to allow other authentication mechanisms).
  • empty password. Whether authentication with an empty password should be allowed or not should be left to the administrator of the system. pam_unix(8) has the nullok option to control this, SSH (when accessing the passwd database directly) has its own option, etc ... unfortunately, it's possible to store an empty password in two different ways:
    • hash of empty string. This seems to happen when an empty password is set via pam_unix(8), e.g. by using passwd(1). I think this is bad, because lots of tools check whether the password field itself (holding the hash) is empty...
    • "null password", actually leaving the password field empty. IMHO, this is the correct way to store an empty password, because tools seem to check for that to explicitly allow or deny empty passwords.
Now, having read some more source code of pam_unix(8), I really think this is a bug. When doing the checks for nullok, it always relies on checking whether the password field in the database (where the hash goes) is empty, therefore all these checks would happily allow an empty password as soon as there is a hash (of the empty string) stored. Still, when setting an empty password using pam_unix(8), it does exactly that: hash that empty string and store the hash 😣

I'll probably do some further tests on my -CURRENT test machine and also test a little patch to make sure empty passwords are stored as empty hashes instead....
 
To disable password-based authentication (i. e. other mechanisms may still grant access):​
Bash:
pw usermod -n myuser -h -
To set a zero-length password (i. e. just typing the username is sufficient for login, there is no password prompt):​
Whilst this is fine for a local login, it does not work for sshd(), even if you PermitEmptyPasswords.

PermitEmptyPasswords
When password authentication is allowed, it specifies whether
the server allows login to accounts with empty password
strings. The default is no.

For this to work maybe /etc/pam.d/sshd (a file I had never previously come acrosss) needs to be amended...

Code:
#
# $FreeBSD$
#
# PAM configuration for the "sshd" service
#

# auth
auth            sufficient      pam_opie.so             no_warn no_fake_prompts
auth            requisite       pam_opieaccess.so       no_warn allow_local
#auth           sufficient      pam_krb5.so             no_warn try_first_pass
#auth           sufficient      pam_ssh.so              no_warn try_first_pass
auth            required        pam_unix.so             no_warn try_first_pass

# account
account         required        pam_nologin.so
#account        required        pam_krb5.so
account         required        pam_login_access.so
account         required        pam_unix.so

# session
#session        optional        pam_ssh.so              want_agent
session         required        pam_permit.so

# password
#password       sufficient      pam_krb5.so             no_warn try_first_pass
password        required        pam_unix.so             no_warn try_first_pass
 
For this to work maybe /etc/pam.d/sshd (a file I had never previously come acrosss) needs to be amended...
Yes, by default the PAM stacks for network services do not allow blank passwords. zirias@ just mentioned the necessary option to pam_unix(8):​
Diff:
--- sshd~       2023-11-22 09:08:08.889676902 +0000
+++ sshd        2023-11-22 09:08:12.681743107 +0000
@@ -9,7 +9,7 @@
 auth            requisite       pam_opieaccess.so       no_warn allow_local
 #auth           sufficient      pam_krb5.so             no_warn try_first_pass
 #auth           sufficient      pam_ssh.so              no_warn try_first_pass
-auth            required        pam_unix.so             no_warn try_first_pass
+auth            required        pam_unix.so             no_warn try_first_pass nullok

 # account
 account         required        pam_nologin.so
NB: nullok applies to all accounts, not just the one you want passwordless. In particular for ssh(1) I recommend doing key-based authentication instead, see ssh-keygen(1). The key might be passwordless.​
 
In particular for ssh(1) I recommend doing key-based authentication instead, see ssh-keygen(1). The key might be passwordless.
I already mentioned it earlier and I really want to emphasize it here again: THIS is most likely the sane solution for the specific scenario. And even passwordless keys can be somewhat risky (if you consider the possibility of leaking the private key), an alternative is to unlock your key only once per session using ssh-agent(1), then it can be used without re-entering the password every time. Another alternative, e.g. for automation where entering a password would be impossible, is to restrict what a key can do in ~/.ssh/authorized_keys, which is documented in sshd(8).

Nevertheless it really seems there is a bug (or, unexpected behavior) regarding setting an empty password through pam_unix(8).
 
You could write [expect](https://man.freebsd.org/cgi/man.cgi?query=expect&apropos=0&sektion=0&manpath=FreeBSD+14.0-RELEASE+and+Ports&arch=default&format=html) script to spawn a process and send "keys\n" and expect "output' and send keys in a programming way.

[A simple example](https://www.baeldung.com/linux/telnet-automate-using-expect) you can reference.
 
yjqg6666 there are ways to "simulate" keypresses in different scenarios of course, but note this unfortunately isn't the root issue of this thread...
balanga authentication with SSH keys is well known and widely used, so I would suggest you first use your trusted web search engine to learn how it works in general, then, if necessary, you can come back here with more specific questions.
bgroper at least I remember this "userfriendly" classic (original page seems to be dead....)

---

Here's some first result of more experimentation with SSH:
  • Configured for direct passwd(5) access only (PasswordAuthentication yes and KbdInteractiveAuthentication no), PermitEmptyPasswords no prevents logins with empty passwords, no matter whether a hash is stored or the hash field is empty (good!), but PermitEmptyPasswords yes only works when there is a hash (of the empty string) stored → weird.
  • Configured for PAM only (PasswordAuthentication no and KbdInteractiveAuthentication yes), it's a bit more complicated...
    • without a hash ("null password"), login works with nullok only when PermitEmptyPasswords is set as well, in which case SSH doesn't even prompt for a password.
    • with a hash (of the empty string), login always works, regardless of both settings, prompting for a password but accepting the empty one.
So, all in all, that's a real mess: It seems SSH expects an empty password to be stored as a hash of the empty string, while our pam_unix(8) on the other hand expects an empty field (no hash at all) in the database, but when given an empty password to set, nevertheless creates and stores a hash. Confusion perfect.

Now I don't even know where to start attempting to fix this all 😣 (edit: maybe the best "action" here would be no action at all. Empty passwords are a footgun anyways, now we know that gun is ill defined and utterly unreliable as well when it comes to the classic passwd database and how different tools handle it ...)
 
What about talking to the upstream SSH people or is this FreeBSD specific?
Our SSH is OpenSSH, so upstream is OpenBSD, it's imported into our tree here: https://cgit.freebsd.org/src/tree/crypto/openssh

OpenBSD doesn't use PAM but has "BSD authentication" instead ... just maybe this adds to the confusion ... :-/ of course, the "portable" version of OpenSSH supports PAM, it's also used in (most?) Linux distributions for example.

In a nutshell, all this mess probably boils down to the fact that you have two possibilities for storing an empty password in passwd(5), and it looks like there's no common agreement which one is the "correct" one. I could still try to at least "fix" the inconsistency in our pam_unix(8), but this would still lead to "surprising" results with e.g. OpenSSH :(
 
Back
Top