LinuxQuestions.org
Visit Jeremy's Blog.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 09-27-2011, 04:26 PM   #1
krisdames
LQ Newbie
 
Registered: Sep 2011
Posts: 2

Rep: Reputation: Disabled
Bash script to accept password and replace characters with * as they are typed


I googled this and couldn't find an answer, so I rolled my own. Here it is, hope it helps. Feel free to improve on it.

Code:
#!/bin/bash
PWORD=
ANYKEY=0
echo -n "Password:  "
until [ -z "$ANYKEY" ]
do
    read -N 1 -s ANYKEY
    echo -n "*"
    PWORD="$PWORD$ANYKEY"
done
echo
echo $PWORD
exit
 
Click here to see the post LQ members have rated as the most helpful post in this thread.
Old 09-27-2011, 04:59 PM   #2
corp769
LQ Guru
 
Registered: Apr 2005
Location: /dev/null
Posts: 5,818

Rep: Reputation: 1007Reputation: 1007Reputation: 1007Reputation: 1007Reputation: 1007Reputation: 1007Reputation: 1007Reputation: 1007
You should incorporate some sort of encryption, due to being a bash script. Sure, you can't see the password, but the plain-text password is being stored in a variable.
 
Old 09-27-2011, 06:53 PM   #3
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,783

Rep: Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083
Quote:
Originally Posted by corp769 View Post
You should incorporate some sort of encryption, due to being a bash script. Sure, you can't see the password, but the plain-text password is being stored in a variable.
But any encryption scheme will require the key to be stored in a variable. You might as well assume that variables are safe.
 
Old 09-28-2011, 12:42 AM   #4
A.Thyssen
Member
 
Registered: May 2006
Location: Brisbane, Australia
Distribution: linux
Posts: 158

Rep: Reputation: 44
Quote:
But any encryption scheme will require the key to be stored in a variable. You might as well assume that variables are safe.
But if the environment the script runs in has declared that PWORD is an environment variable then the password will appear in the process listing :-)

But generally yes you can assume variables are safe, as only someone with root access to your machine and thus to memory, or disk swap space, has any chance of recovering the password.

However if you can it is better to store them in some less obvious but simple form of encryption. And clear the password, before unsetting the variable (if the language allows it, as some languages just allocate new memory rather than overwrite old memory) as soon as you are finished with it.

Also in shell never use anything other than a built-in "echo" command to feed that password to some other program, or it will appear in the process table.

The better idea is not to store them at all but pipe the password direct from your password input program/function to the program that will use it. Of course if you need to use the password multiple times, then storing it in a variable may ba a lot easier than attempting some type of 'pipeline tee processing' methods.

Many commands that need a password will have options to read from a pipe or special file descriptor for the password to use. Use it as it is about the safest way to use the password.

If the program insists on reading from a TTY (user input only) used programs like "unbuffer" (from the "expect" package) to wrap the program in a TTY so you can pipe the password into the program. I have also used the use "expect" directly for PTY wrappers, but the new method is to use the "socat" command (a advanced "netcat" replacement) to do PTY wrappers around commands.

---

Also if you are reading individual characters yourself then YOU will need to handle normal terminal control characters such as backspace, delete, and ^U (kill input)

Type this ab{delete}{delete}cd{enter}
and you will see "cd" returned.

Now pipe the output though "od" (modify the script) and you find the password contains much more than just two letters!

Yes you could use such characters in a password, but typing them in most password readers just does not work very well. If you plan to use control characters in passwords, you may as will be giving your password in hex or base64, to make it more manageable.

It is far easier just to read direct from a TTY with echo turned off, and let the system do the work for you. It is much easier, and I have done this many times in many languages.

---

The better solution for password reading is to use programs that are designed for this, which generally pipe the password to stdout.
Examples include...
/usr/libexec/openssh/x11-ssh-askpass
/usr/libexec/openssh/ssh-askpass
/usr/bin/ssh-askpass
/usr/libexec/openssh/gnome-ssh-askpass
/usr/lib/openssh/gnome-ssh-askpass
zenity --title=Program --entry --text=Password: --hide-text
Xdialog --title Program --stdout --password --inputbox "Password:" 0x0
{ echo "SETDESC password:"; echo "GETPIN"; } | pinentry | sed -n 's/^D //p'

and probably many many others that essentially does exactly what your script is trying to do. I have often written encrypting and mounting scripts that search to find at least one of these programs to use for user password input.

For an example: the script "mount_encrypted" in my WWW software export looked for at least one of the programs listed above to get a password from the user.

http://www.ict.griffith.edu.au/antho...ount_encrypted

Many systems actually specify the password reading program to use in the SSH_ASSPASS environment variable (set during system login), which lets the user override the method by which passwords will be entered, and let them use other password control systems, and keyrings. However few programs needing passwords will use that environment variable :-(

Of course if X windows is not enable you will need to fall back to some form of TTY method, or even a curses method such as "dialog".

---

Anyone else have password reading or handling solutions?

Last edited by A.Thyssen; 09-28-2011 at 01:44 AM.
 
Old 09-28-2011, 04:27 AM   #5
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by corp769 View Post
You should incorporate some sort of encryption, due to being a bash script. Sure, you can't see the password, but the plain-text password is being stored in a variable.
Variables aren't part of the environment unless they're exported. unset PWORD at the top instead of PWORD= would be sufficient to keep it from being read via /proc/pid/environ.
Kevin Barry
 
Old 09-28-2011, 04:47 AM   #6
druuna
LQ Veteran
 
Registered: Sep 2003
Posts: 10,532
Blog Entries: 7

Rep: Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405
Hi,

Have a look at this:
Code:
#!/bin/bash

unset password

prompt="Enter Password : "
while IFS= read -p "$prompt" -r -s -n 1 char
do
    if [[ $char == $'\0' ]]
    then
        break
    fi
    prompt='*'
    password+="$char"
done

echo
echo "Password=$password"
Quote:
You need to unset IFS or add IFS= to your while loop otherwise your loop will prematurely break on passwords that contain spaces. Also, you should add the -r flag to read so that passwords can contain backslashes.
Hope this helps.
 
1 members found this post helpful.
Old 09-28-2011, 05:06 AM   #7
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by druuna View Post
Code:
#!/bin/bash

unset password

prompt="Enter Password : "
while IFS= read -p "$prompt" -r -s -n 1 char
do
    if [[ $char == $'\0' ]]
    then
        break
    fi
    prompt='*'
    password+="$char"
done

echo
echo "Password=$password"
Why don't you quote $char and check for $'\n'? I don't understand the check for null and I'm not sure how $IFS comes into play here (nothing that quoting can't fix, anyway). read only splits based on newlines by default. Also, what about backspaces? I often mistype a password and hold Backspace for a few seconds to clear what I've typed.
Kevin Barry
 
Old 09-28-2011, 05:38 AM   #8
druuna
LQ Veteran
 
Registered: Sep 2003
Posts: 10,532
Blog Entries: 7

Rep: Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405
Hi,
Quote:
Originally Posted by ta0kira View Post
Why don't you quote $char and check for $'\n'? I don't understand the check for null
When enter/return is pressed, the variable holds NULL ('\0'). I cannot get this to work using \n (or \r).

Using set -x might help to show what is being done/compared.

Quote:
I'm not sure how $IFS comes into play here (nothing that quoting can't fix, anyway). read only splits based on newlines by default.
IFS is explained in my previous post.

This is just one way of doing what the OP asked. There probably are other ways. Feel free to edit/improve what I posted

Quote:
Also, what about backspaces? I often mistype a password and hold Backspace for a few seconds to clear what I've typed.
Backspacing works Ok, to be fair, the stars aren't removed when using the backspace key, but the actual content is removed.

Hope this clears things up a bit.
 
2 members found this post helpful.
Old 09-28-2011, 07:27 AM   #9
corp769
LQ Guru
 
Registered: Apr 2005
Location: /dev/null
Posts: 5,818

Rep: Reputation: 1007Reputation: 1007Reputation: 1007Reputation: 1007Reputation: 1007Reputation: 1007Reputation: 1007Reputation: 1007
So I sleep for 13 hours, and I log in, and see what I started... LOL

Everyone pretty much hit the nail on the head about this. A.Thyssen summed up pretty much what I wanted to say, and Druuna did the modification that I was going to do last night. Not no more.... I hate new medications; Sometimes, they mess with your body that bad that you sleep.... Oh well. Anyway, Good job on the script!
 
Old 09-28-2011, 08:57 AM   #10
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by druuna View Post
When enter/return is pressed, the variable holds NULL ('\0'). I cannot get this to work using \n (or \r).
If you use -d$'\r' with read then it works with [[ "$char" == $'\n' ]] without setting IFS.
Kevin Barry
 
1 members found this post helpful.
Old 09-28-2011, 09:23 AM   #11
druuna
LQ Veteran
 
Registered: Sep 2003
Posts: 10,532
Blog Entries: 7

Rep: Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405Reputation: 2405
Hi,
Quote:
Originally Posted by ta0kira View Post
If you use -d$'\r' with read then it works with [[ "$char" == $'\n' ]] without setting IFS.
Kevin Barry
What does your read line look like?

I still need to use IFS:
Code:
# This doesn't work (return is not recognized):
while read -p "$prompt" -d$'\r' -r -s -n 1 char
and
if [[ "$char" == $'\n' ]]

# This does work:
while IFS= read -p "$prompt" -d$'\r' -r -s -n 1 char
and
if [[ "$char" == $'\n' ]]
 
Old 09-28-2011, 11:31 AM   #12
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by druuna View Post
Hi,
What does your read line look like?
It turns out I did IFS= to test out your code, and then I forgot to set it back when I started messing around. That means I was incorrect!
Kevin Barry
 
Old 09-29-2011, 02:49 AM   #13
A.Thyssen
Member
 
Registered: May 2006
Location: Brisbane, Australia
Distribution: linux
Posts: 158

Rep: Reputation: 44
Quote:
Originally Posted by druuna View Post
Backspacing works Ok, to be fair, the stars aren't removed when using the backspace key, but the actual content is removed.
NO it does not. it only appears to!

Add the line...
echo "Password length = $(echo -n "$password" | wc -c)"

and then try to use lots of backspaces to clear the password!
You will find you have a password filled with backspaces!

When reading input character by character you remove the ability of read (or the tty handler) from actually actioning backspaces.

The read doesn't have the backspace to make use them later - you will need to do it! Don't forget to action both BACKSPACE (control-H) and DELETE (control-?)

Last edited by A.Thyssen; 10-02-2011 at 11:32 PM.
 
Old 09-29-2011, 03:25 AM   #14
A.Thyssen
Member
 
Registered: May 2006
Location: Brisbane, Australia
Distribution: linux
Posts: 158

Rep: Reputation: 44
If you are going to match on a RETURN character, I would also try to match on NEWLINE
so that passwords being feed via a pipeline (stream) will end the password read.

It may also be a good idea to also include CONTROL-D and NULL as well just to be sure!


A closely related question, that may help -- get read to simple read every character regardless of what it is, including NULL. It should return false only on EOF.

For example...
Code:
   printf 'a\tb\rc\nd\0e' | 
     while IFS= read -r -s -n 1 char
     do
       echo -n '*'
     done
     echo
   *********
Nine successfull reads... Nine stars out!

Aside from the above... Note that "echo" can not print NULL characters, but the printf builtin can.

EDIT: Also see next, variables can not hold NULL characters either!

Last edited by A.Thyssen; 10-02-2011 at 11:33 PM.
 
Old 09-30-2011, 02:33 AM   #15
A.Thyssen
Member
 
Registered: May 2006
Location: Brisbane, Australia
Distribution: linux
Posts: 158

Rep: Reputation: 44
After further investigation the test in the above scripts...
Code:
if [[ $char == $'\0' ]]
Does NOT do what you expect it to do.

It for NOT test for a NULL character but is equivalent to a test for a NULL string.

For example
Code:
   c=''
   [[ $c == $'\0' ]] && echo true
true
The test may as well be a simplier 'empty string test'
As such a more correct test of the above is...
[[ "$char" == '' ]] && echo true

Last edited by A.Thyssen; 09-30-2011 at 02:51 AM.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Weird characters get typed in terminal sumeet inani Linux - Newbie 8 03-11-2010 10:06 PM
How do I replace special characters in a string within a bash script? rhaup0317 Linux - Newbie 2 06-03-2008 11:56 AM
How to modify the names of files and replace characters with other characters or symb peter88 Linux - General 2 12-10-2006 03:05 AM
sed doesn't accept $variable in bash script chii-chan Programming 6 05-28-2005 07:07 AM
bash script to accept input ONLY until background process completes andrewstr Linux - Software 2 03-17-2004 12:02 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 04:22 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration