This is an old revision of the document!
Table of Contents
A Better "getpass()" Function for Unix
What is This About?
I've had this problem in the past and it cropped up again today and pissed me off once again so I decided to tackle the issue. The issue is the Python standard library version of getpass()
from the getpass
module. It works fine in terms of really basic usage, but the big problem comes when you want to write a script that reads from STDIN
and calls getpass()
. Since the built in getpass()
reads from STDIN
, it ends up borking your script. Now, for anyone who has ever used ssh
before (and I assume if you are reading this, you have), you will have noticed that the ssh
client gets around this very issue since you can pipe info to ssh
and enter your password when prompted. This is due to the fact that ssh
client reads and writes directly to your terminal, rather than reading and writing from STDIN
and STDOUT
. This is exactly what I've done with my version of getpass()
. I used most of the code used in the standard library getpass()
, but made it write the prompt and read directly from a connection to the terminal itself. This has been tested on linux (Gentoo) and FreeBSD 6.2 and it works fine on both.
The Code
Here is my simple version of the standard library getpass()
. Of course, this will only work on a *nix platform.
def getPass(prompt='Password: '): """ Writes the password prompt and reads from terminal directly, just like the openssh client """ if not os.isatty(sys.stdout.fileno()): raise IOError , 'You can only call getPass() from a tty' ttyname = os.ttyname(sys.stdout.fileno()) ttyh = open(ttyname , 'w+b') ttyfd = ttyh.fileno() old = termios.tcgetattr(ttyfd) # a copy to save new = old[:] new[3] = new[3] & ~termios.ECHO # 3 == 'lflags' try: termios.tcsetattr(ttyfd , termios.TCSADRAIN, new) ttyh.write(prompt) ttyh.flush() passwd = ttyh.readline().strip() finally: termios.tcsetattr(ttyfd , termios.TCSADRAIN, old) ttyh.close() sys.stdout.write('\n') return passwd