Can you portably read sensitive input from the commandline? - security

The bash builtin read has a flag -s that prevents it from echoing whatever is being read from the commandline. After searching opengroup.org and filtering through all the other meanings for read, I still haven't found a POSIX/portable equivalent. Is there a reasonable way to do this?
In bash it's easy enough:
$ bash -c 'read -sp "What is your password? " password; printf "\n%s\n" "$password"'
What is your password?
I'll never tell!
But in sh…
$ dash -c 'printf "What is your password? "; read password >/dev/null 2>&1; printf "\n%s\n" "$password"'
What is your password? I'll never tell!
I'll never tell!

So the answer to your question is as described in this link
you can turn off by using builtin command stty
stty -echo
ps:
dont forget to save your previous settings
old_set=$(stty -g)
stty -echo
read -r password
stty "$old_set"

Related

How to 'read -s' in shell?

I know that user input can be read silently using bash with read -s someVar and I was wondering if there is a /bin/sh equivalent that allows user input without displaying it on the command line?
Note: I am just curious if /bin/sh read supports this feature somehow.
Use the stty command to turn off echoing of typed characters.
get_entry () {
printf "Choose: "
stty -echo
IFS= read -r choice
stty echo
printf '\n'
}
get_entry
printf "You chose %s\n" "$choice"

In Bash, how can I output a new line after read -es?

current code:
echo -n "password: "
read -es password
echo -n "ok"
behavoir in linux:
password: ok
Can we make it like:
password:
ok
thanks,
wxie
The following will work:
read -p "password: " -es password
echo
echo "ok"
Maybe:
read -p "password: " -es password
printf "\n ok \n"
If you want a newline before the OK, this should do it:
echo -e "\nok"
The -e enables interpretation of the backslash codes.
From echo's man page: -n do not output the trailing newline. Try it without the option.
We can use \n as a line separator in printf, there is an extra line for padding after "ok" which you can remove
printf "password: " && read -es password && printf "\n\nok\n"
If you are saving a password this way it would still be contained in the variable $password in plain text, the string below would print it openly.
printf "$password"
Your code sample uses echo and should be using printf, there are articles on echo's POSIX compliance, echo could work like Greg Tarsa points out, but not all versions are built with switch options like -e or -n.
I find it readable to use printf, also other "languages" have similar commands such as PRINT, print, println, print() and others.
If you need to use echo you could
echo -n "password: " && read -es password && echo -e "\nok\n"

Write script to create multiple users with pre-defined passwords

So I would like to make a script that create users from users.txt running
useradd -m -s /bin/false users_in_the_users.txt
and fill the password from passwords.txt twice (to confirm the passwords)
This is the script
#!/bin/bash
# Assign file descriptors to users and passwords files
exec 3< users.txt
exec 4< passwords.txt
exec 5< passwords.txt
# Read user and password
while read iuser <&3 && read ipasswd <&4 ; do
# Just print this for debugging
printf "\tCreating user: %s with password: %s\n" $iuser $ipasswd
# Create the user with adduser (you can add whichever option you like)
useradd -m -s /bin/false $iuser
# Assign the password to the user, passwd must read it from stdin
passwd $iuser
done
The problem is, it does not fill the passwords. And 1 more thing, I want the script to fill the passwords twice.
Any suggestions?
You have to supply the password on stdin. Replace:
passwd $iuser
with:
passwd "$iuser" <<<"$ipasswd
$ipasswd"
or, as suggested by mklement0:
passwd "$iuser" <<<"$ipasswd"$'\n'"$ipasswd"
The incantation <<< creates a here-string. The string that follows the <<< is provided as standard in to the command which precedes the <<<. In this case we provide the two copies of the password that the passwd command wants.
(The script reads these passwords from a plain text file. I will assume that your situation is some special case for which this is not as dangerous as it normally would be.)
John1024's answer is the correct one - his warning about reading passwords from plain-text files bears repeating.
Let me show the solution in context, without the file-descriptor acrobatics (exec 3<, ...):
#!/bin/bash
# NOTE: Be sure to run this script with `sudo`.
# Read user and password
while read iuser ipasswd; do
# Just print this for debugging.
printf "\tCreating user: %s with password: %s\n" $iuser $ipasswd
# Create the user with adduser (you can add whichever option you like).
useradd -m -s /bin/false $iuser
# Assign the password to the user.
# Password is passed via stdin, *twice* (for confirmation).
passwd $iuser <<< "$ipasswd"$'\n'"$ipasswd"
done < <(paste users.txt passwords.txt)
paste users.txt passwords.txt reads corresponding lines from the two files and puts them on a single line, separated with \t.
The result is piped to stdin via a process substitution (<(...)).
This allows read to read from a single source.
$\n is an ANSI C-quoted string that produces a (literal) newline.
#! /bin/bash
for i in {1..100}
do
`sudo mkdir -p /root/Desktop/userm$i`
`sudo useradd -m -d /root/Desktop/userm$i -s /bin/bash userm$i`
echo "userm$i:userm$i" | chpasswd
done
this will create 100 users. user name will be (userm1-userm100). home directory will be /root/Desktop/(userm1-user100)
password will be (userm1-userm100)
Instead of using this line:
useradd -m -s /bin/false $iuser
Try this one:
useradd -m -s /bin/false -p $ipasswd $iuser
You don't actually need this:
passwd $iuser <<< "$ipasswd"$'\n'"$ipasswd"
Kindly run the below script.
#!/bin/bash
#purpose: bash script to create multiple users with pre-defined passwords at once.
#Read_Me: The import file should be in two columns, first users name and second passwords.
#author: Bablish Jaiswal
#contact: linux.cnf#gmail.com
read -p "Kindly import/type Users Name-password file with location:- " creation_info
cat $creation_info |while read i p
do
( useradd $i && echo -e "${p}\n${p}" | passwd $i ) > /dev/null 2>&1 && echo $user ${i} created and password is ${p} || echo ${i} failed
done

read -p returns "read: no query process" using korn shell ksh

created a simple shell file that contains this:
read -p ThePrompt TheSomthing
echo $TheSomething
Run it, and it returns
-ksh[1]: read: no query process
I've tried single quotes, double quotes around ThePrompt and the man page specifically says "-p" is to use a prompt but it is not working for me. Can anyone tell me what I'm doing wrong? Thanks!
In Ksh you can use this format:
echo "ThePrompt\c"
read TheSomthing
echo $TheSomething
From the googled man page:
The -un and -p options cause input to be read from file descriptor n or the current co-process (see Co-Processes above for comments on this), respectively. If the -s option is used, input is saved to the history file.
To use a prompt, write this instead:
read TheSomething?'ThePrompt'
I found a word around:
echo -n 'prompt: '
read input1
echo -n 'prompt: '
read input2
.
.
.
I don't know why the -p doesn't work as described in the man page. If anyone out there has insights, please reply.
Thanks!
Sorry for reviving this question, but I do my shell scripts in KSH, so I was in the same predicament, until I came with this.
My solution to capture a single character:
$> echo -e "My prompt: \c" ; read -n 1 -s -r FOO ; echo -e "\b"
My prompt:
$> echo $FOO
d
$>
For a longer string remove the "-n 1" from the read command:
$> echo -e "My prompt: \c" ; read -s -r FOO ; echo -e "\b"
My prompt:
$> echo $FOO
this is my entry!!!
$>
I hope this is what you were looking for... Cheers!

How to read just a single character in shell script

I want similar option like getche() in C. How can I read just a single character input from command line?
Using read command can we do it?
In bash, read can do it:
read -n1 ans
read -n1 works for bash
The stty raw mode prevents ctrl-c from working and can get you stuck in an input loop with no way out. Also the man page says stty -raw is not guaranteed to return your terminal to the same state.
So, building on dtmilano's answer using stty -icanon -echo avoids those issues.
#/bin/ksh
## /bin/{ksh,sh,zsh,...}
# read_char var
read_char() {
stty -icanon -echo
eval "$1=\$(dd bs=1 count=1 2>/dev/null)"
stty icanon echo
}
read_char char
echo "got $char"
In ksh you can basically do:
stty raw
REPLY=$(dd bs=1 count=1 2> /dev/null)
stty -raw
read -n1
reads exactly one character from input
echo "$REPLY"
prints the result on the screen
doc: https://www.computerhope.com/unix/bash/read.htm
Some people mean with "input from command line" an argument given to the command instead reading from STDIN... so please don't shoot me. But i have a (maybe not most sophisticated) solution for STDIN, too!
When using bash and having the data in a variable you can use parameter expansion
${parameter:offset:length}
and of course you can perform that on given args ($1, $2, $3, etc.)
Script
#!/usr/bin/env bash
testdata1="1234"
testdata2="abcd"
echo ${testdata1:0:1}
echo ${testdata2:0:1}
echo ${1:0:1} # argument #1 from command line
Execution
$ ./test.sh foo
1
a
f
reading from STDIN
Script
#!/usr/bin/env bash
echo please type in your message:
read message
echo 1st char: ${message:0:1}
Execution
$ ./test.sh
please type in your message:
Foo
1st char: F

Resources