How to get a password from a shell script without echoing - solutions

#!/bin/bash
# Read Password
echo -n Password: 
read -s password
echo
# Run Command
echo $password

#!/bin/bash
stty -echo
printf "Password: "
read PASSWORD
stty echo
printf "\n"
 
read -s -p "Password: " password
$ help read
read: read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]
Read a line from the standard input and split it into fields.
  ...
  -p prompt output the string PROMPT without a trailing newline before
            attempting to read
  ...
  -s                do not echo input coming from a terminal
#!/bin/sh

# Read secret string
read_secret()
{
    # Disable echo.
    stty -echo

    # Set up trap to ensure echo is enabled before exiting if the script
    # is terminated while echo is disabled.
    trap 'stty echo' EXIT

    # Read secret.
    read "$@"

    # Enable echo.
    stty echo
    trap - EXIT

    # Print a newline because the newline entered by the user after
    # entering the passcode is not echoed. This ensures that the
    # next line of output begins at a new line.
    echo
}


You can also prompt for a password without setting a variable in the current shell by doing something like this:

$(read -s;echo $REPLY)

For instance:

my-command --set password=$(read -sp "Password: ";echo $REPLY)

You can add several of these prompted values with line break, doing this:

my-command --set user=$(read -sp "`echo $'\n '`User: ";echo $REPLY) --set password=$(read -sp "`echo $'\n '`Password: ";echo $REPLY)

 

 

Basic ways you can use shell scripts to monitor password strength and secret accounts.

The internet ain't what it used to be back in the old days. I remember being online back when it was known as ARPAnet actually—back when it was just universities and a handful of corporations interconnected. Bad guys sneaking onto your computer? We were living in blissful ignorance then.

Today the online world is quite a bit different, and a quick glimpse at the news demonstrates that it's not just global, but that bad actors, as they say in security circles, are online and have access to your system too. The idea that any device that's online is vulnerable is more true now than at any previous time in computing history.

Fortunately, a lot of smart people are working on security both for networks and Internet of Things devices. We don't want hackers gaining control of our smart homes or autonomous cars.

Whether you have Linux running on your laptop or ancient PC file server or whether you're managing a data center, your system is also vulnerable to malicious users. I can't offer any sort of robust solution in this article, but let's have a look at some basic things you can do with shell scripts to keep an eye on your system.

First and foremost, make sure you have complex non-guessable passwords for all your accounts and particularly your administrative or root account. It's tough to check existing passwords, since they're all stored in an encrypted manner without spending oodles of CPU cycles brute-forcing it, but how about a script where users can enter their password and it'll confirm whether it's hard to guess?

Password Tester

The general rule of thumb with modern password creation is that you should use a combination of uppercase, lowercase, digits and one or more punctuation characters, and that the password should be longer, not shorter. So "meow" is horrible as a password, and "Passw0rd!" is pretty good, but "F#g_flat_33" is a secure choice.

First things first though. A script that is checking passwords should let users enter their password choice invisibly. You can do so with the stty command:


stty -echo
echo -n "Enter password: "
read password
stty echo

Now the algorithmic approach to testing for a particular type of character is simple. Remove every occurrence of that particular character in the user input and compare it to the original. If they're the same, the user didn't actually use that particular class of characters.

For example, here's the code to test for the presence of lowercase letters:


chop=$(echo "$password" | sed -E 's/[[:lower:]]//g')
echo "chopped to $chop"

if [ "$password" == "$chop" ] ; then
  echo "Fail: You haven't used any lowercase letters."
fi

Notable here is the use of what are known as bracket expressions. Notice I didn't specify [a-z] above, but rather used the locale-smart range :lower:. In a regular expression, that would have a pair of square brackets around it: [:lower:]. But, since it's part of a search and replace pattern for sed, it picks up a second pair of square brackets too: [[:lower:]].

It turns out there are a lot of bracket expressions, so you can use :upper: to test for uppercase, :lower: for lowercase letters, :digit: for the digits and :punct: for punctuation. There are plenty more, but those will suffice for the scope of this article.

The good news is that it's straightforward to write a function that will check for the specified bracket expression and output an appropriate error as, well, appropriate:


checkfor()
{
  pattern="$1"
  errormsg="$2"

  sedpattern="s/$pattern//g"

  chop=$(echo "$password" | sed -E $sedpattern)

  if [ "$password" == "$chop" ] ; then
    echo "Fail: You haven't used any ${errormsg}."
  fi
}

Then you can invoke it like this:


checkfor "[[:lower:]]" "lowercase letters"
checkfor "[[:upper:]]" "uppercase letters"
checkfor "[[:digit:]]" "digits"
checkfor "[[:punct:]]" "punctuation"

Nice and short. So, let's give this script a quick test at the command line with the password "B3g":


$ sh checkpw.sh
Enter password:
You entered B3g
Fail: You haven't used any punctuation.

An accurate error message. In the final script, of course, you won't echo the entered password, as that's not so good from a privacy and security perspective.

To test for length, it's easy to use wc -c, but there's a special variable reference format in shell scripts that offers access to the number of characters too: ${#xxx}. For example, consider this brief snippet:


$ test="Hi Mom"
$ echo ${#test}
6

With this in mind, the test to see whether a specified sample password is at least eight characters long is easily coded as:


if [ ${#password} -lt $minlength ] ; then
  echo "Fail: Password must be $minlength characters."
fi

Set the $minlength variable to something reasonable at the top of the script. I suggest 8 as a good minimum length.

I designed the script here to be purely informational, and if you use a terrible password like "kitty", you're going to see a lot of errors:


$ sh checkpw.sh
Enter password:
You entered kitty
Fail: You haven't used any uppercase letters.
Fail: You haven't used any digits.
Fail: You haven't used any punctuation.
Fail: Password must be at least 8 characters.

There are plenty of tweaks you can make if you want, ranging from having a counter that can tell if there were more than zero errors with a resultant success message if all tests succeed to having the script quit as soon as the first error condition is encountered.

Now, with this script as a simple password-testing tool, it's easy to request every user set up a new, secure password that passes all these tests.

New Account Creation

Another way to keep an eye on your system is to get a notification any time a new account is created. Whether or not you're the only admin, that shouldn't be something that happens too often. But, if you are the only admin and it happens without you knowing? Danger, Will Robinson!

In the old days, salted (encrypted) passwords were part of what was stored in /etc/passwd, but modern systems keep that encrypted data more safely tucked away in /etc/shadow. User accounts, however, still show up in the /etc/passwd file, so you can use that as the basis for this simple script.

The idea is that you're going to grab all the user account names and save them to a hidden file, and every time you run the script, you'll compare the latest to the saved. If there are new entries, that's bad!

This approach is definitely not robust, of course, and I wouldn't trust credit report data servers with a tool this lightweight, but it's an interesting script to consider nonetheless.

Let's see how to pull out just user account names from the file:


$ cat /etc/passwd | cut -d: -f1
root
bin
daemon
adm
. . .

It's all about that cut command! The -d flag specifies the field delimiter, and -f1 requests that just the first field is output. Given an input line like this:


root:x:0:0:root:/root:/bin/bash

you can see that the output becomes just the account names. This script could compare full files—heck, there's even a Linux command for the job—but you don't want to get false positives if users change their user names but otherwise leaves their accounts intact. Further, I like clean, readable output, so that's what this will produce.

Here's the full script:


#!/bin/sh

# watch accounts - keep an eye on /etc/passwd,
#                  report if accounts change

secretcopy="$HOME/.watchdb"
tempfile="$HOME/.watchdb.new"
passwd="/etc/passwd"
compare=0               # by default, don't compare

trap "/bin/rm -f $tempfile" 0

if [ -s "$secretcopy" ] ; then
  lastrev="$(cat $secretcopy)"
  compare=1
fi

cat $passwd | cut -d: -f1 > $tempfile

current="$(cat $tempfile)"

if [ $compare -eq 1 ] ; then
  if [ "$current" != "$lastrev" ] ; then
    echo "WARNING: password file has changed"
    diff $secretcopy $tempfile | grep '^[<>]' |
        sed 's/</Removed: /;s/>/Added:/'
  fi
else
   mv $tempfile $secretcopy
fi

exit 0

This is a pretty simple script, all in all. Close inspection will reveal that the secret copy of accounts will be saved in $HOME/.watchdb. The trap command is used to ensure that the temp file is removed when the script finishes up, of course.

The $compare variable relates to the case when it's the very first time you run the script. In that situation, there is no .watchdb, so it can't be used to test or compare. Otherwise, the contents of that file are stored in the local variable $secretcopy and $compare is set to 1.

Block two is the actual comparison, and the only part that's interesting is the invocation of diff to compare the two files:


diff $secretcopy $tempfile | grep '^[<>]' |
   sed 's/</Removed: /;s/>/Added:/'

diff by default outputs commands for the ancient ed editor, so you mask that out by considering only lines that begin with a < or >. Those denote entries that are only in the old version of the password file (removed in the current live copy) and those only in the new, live version (added accounts).

That's it. Let's run it once to create the secret archive file, then I'll change the password file to remove one account and create another, then run the script again:


$ sh watchaccounts.sh
$
edit password file
$ sh watchaccounts.sh
WARNING: password file has changed
Removed: johndoe
Added: hack3r666

Nice, eh? Now, there are some useful additions to the script that you might consider, notably encrypting .watchdb for security and adding a prompt or command flag to update the secret password file after changes have been reported.

 
 
0 (0)
Article Rating (No Votes)
Rate this article
Attachments
There are no attachments for this article.
Comments
There are no comments for this article. Be the first to post a comment.
Full Name
Email Address
Security Code Security Code
Related Articles RSS Feed
Linux / UNIX: Convert Epoch Seconds To the Current Time
Viewed 3121 times since Fri, May 25, 2018
Adding a range of IPs in Linux
Viewed 2750 times since Mon, May 21, 2018
30 Handy Bash Shell Aliases For Linux / Unix / MacOS
Viewed 4908 times since Thu, Feb 11, 2021
perl podstawy
Viewed 2105 times since Mon, May 21, 2018
HowTo: Clear BASH History
Viewed 2239 times since Mon, Feb 18, 2019
30 Examples for Awk Command in Text Processing
Viewed 15408 times since Sat, Nov 24, 2018
Usuwanie spacji z zmiennych w bash
Viewed 2558 times since Tue, May 22, 2018
Linux and Unix xargs command tutorial with examples
Viewed 3959 times since Fri, Jun 1, 2018
How to sort IP addresses in Linux
Viewed 4022 times since Thu, May 24, 2018
Bash: String Length – How To Find Out
Viewed 2280 times since Mon, Feb 18, 2019