blob: 6ec6c78824b784619835f97e84ae34fc7af83687 [file] [log] [blame]
Guido van Rossumb5903ac1998-04-09 20:37:16 +00001"""Utilities to get a password and/or the current user name.
2
Christian Heimes81ee3ef2008-05-04 22:42:01 +00003getpass(prompt[, stream]) - Prompt for a password, with echo turned off.
4getuser() - Get the user name from the environment or password database.
5
6GetPassWarning - This UserWarning is issued when getpass() cannot prevent
7 echoing of the password contents while reading.
Guido van Rossumb5903ac1998-04-09 20:37:16 +00008
Jeremy Hylton88d23301999-10-18 22:25:22 +00009On Windows, the msvcrt module will be used.
10On the Mac EasyDialogs.AskPassword is used, if available.
11
Guido van Rossumb5903ac1998-04-09 20:37:16 +000012"""
13
Guido van Rossum98d9fd32000-02-28 15:12:25 +000014# Authors: Piers Lauder (original)
15# Guido van Rossum (Windows support and cleanup)
Christian Heimes81ee3ef2008-05-04 22:42:01 +000016# Gregory P. Smith (tty support & GetPassWarning)
Guido van Rossum98d9fd32000-02-28 15:12:25 +000017
Christian Heimes81ee3ef2008-05-04 22:42:01 +000018import os, sys, warnings
Guido van Rossumb5903ac1998-04-09 20:37:16 +000019
Christian Heimes81ee3ef2008-05-04 22:42:01 +000020__all__ = ["getpass","getuser","GetPassWarning"]
21
22
23class GetPassWarning(UserWarning): pass
24
Skip Montanaroeccd02a2001-01-20 23:34:12 +000025
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000026def unix_getpass(prompt='Password: ', stream=None):
Tim Peters07e99cb2001-01-14 23:47:14 +000027 """Prompt for a password, with echo turned off.
Guido van Rossumb5903ac1998-04-09 20:37:16 +000028
Christian Heimes81ee3ef2008-05-04 22:42:01 +000029 Args:
30 prompt: Written on stream to ask for the input. Default: 'Password: '
31 stream: A writable file object to display the prompt. Defaults to
32 the tty. If no tty is available defaults to sys.stderr.
33 Returns:
34 The seKr3t input.
35 Raises:
36 EOFError: If our input tty or stdin was closed.
37 GetPassWarning: When we were unable to turn echo off on the input.
38
39 Always restores terminal settings before returning.
Tim Peters07e99cb2001-01-14 23:47:14 +000040 """
Christian Heimes81ee3ef2008-05-04 22:42:01 +000041 fd = None
42 tty = None
R David Murray319d58d2013-04-08 01:48:22 -040043 passwd = None
Tim Peters07e99cb2001-01-14 23:47:14 +000044 try:
Christian Heimes81ee3ef2008-05-04 22:42:01 +000045 # Always try reading and writing directly on the tty first.
46 fd = os.open('/dev/tty', os.O_RDWR|os.O_NOCTTY)
47 tty = os.fdopen(fd, 'w+', 1)
48 input = tty
49 if not stream:
50 stream = tty
Andrew Svetlov3438fa42012-12-17 23:35:18 +020051 except OSError as e:
Christian Heimes81ee3ef2008-05-04 22:42:01 +000052 # If that fails, see if stdin can be controlled.
53 try:
54 fd = sys.stdin.fileno()
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +000055 except (AttributeError, ValueError):
Christian Heimes81ee3ef2008-05-04 22:42:01 +000056 passwd = fallback_getpass(prompt, stream)
57 input = sys.stdin
58 if not stream:
59 stream = sys.stderr
Guido van Rossumb5903ac1998-04-09 20:37:16 +000060
Christian Heimes81ee3ef2008-05-04 22:42:01 +000061 if fd is not None:
62 passwd = None
63 try:
64 old = termios.tcgetattr(fd) # a copy to save
65 new = old[:]
Senthil Kumaranea8b0242011-03-24 22:27:01 +080066 new[3] &= ~termios.ECHO # 3 == 'lflags'
Gregory P. Smith50467882009-11-01 18:42:17 +000067 tcsetattr_flags = termios.TCSAFLUSH
68 if hasattr(termios, 'TCSASOFT'):
69 tcsetattr_flags |= termios.TCSASOFT
Christian Heimes81ee3ef2008-05-04 22:42:01 +000070 try:
Gregory P. Smith50467882009-11-01 18:42:17 +000071 termios.tcsetattr(fd, tcsetattr_flags, new)
Christian Heimes81ee3ef2008-05-04 22:42:01 +000072 passwd = _raw_input(prompt, stream, input=input)
73 finally:
Gregory P. Smith50467882009-11-01 18:42:17 +000074 termios.tcsetattr(fd, tcsetattr_flags, old)
75 stream.flush() # issue7208
Florent Xicluna54540ec2011-11-04 08:29:17 +010076 except termios.error:
Christian Heimes81ee3ef2008-05-04 22:42:01 +000077 if passwd is not None:
78 # _raw_input succeeded. The final tcsetattr failed. Reraise
79 # instead of leaving the terminal in an unknown state.
80 raise
81 # We can't control the tty or stdin. Give up and use normal IO.
82 # fallback_getpass() raises an appropriate warning.
83 del input, tty # clean up unused file objects before blocking
84 passwd = fallback_getpass(prompt, stream)
Guido van Rossumb5903ac1998-04-09 20:37:16 +000085
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000086 stream.write('\n')
Tim Peters07e99cb2001-01-14 23:47:14 +000087 return passwd
Guido van Rossumb5903ac1998-04-09 20:37:16 +000088
89
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000090def win_getpass(prompt='Password: ', stream=None):
Tim Peters07e99cb2001-01-14 23:47:14 +000091 """Prompt for password with echo off, using Windows getch()."""
Guido van Rossum60250e22001-08-30 15:07:44 +000092 if sys.stdin is not sys.__stdin__:
Christian Heimes81ee3ef2008-05-04 22:42:01 +000093 return fallback_getpass(prompt, stream)
Tim Peters07e99cb2001-01-14 23:47:14 +000094 import msvcrt
95 for c in prompt:
Christian Heimes0ec88b32007-12-10 17:02:00 +000096 msvcrt.putwch(c)
Tim Peters07e99cb2001-01-14 23:47:14 +000097 pw = ""
98 while 1:
Christian Heimes0ec88b32007-12-10 17:02:00 +000099 c = msvcrt.getwch()
Tim Peters07e99cb2001-01-14 23:47:14 +0000100 if c == '\r' or c == '\n':
101 break
102 if c == '\003':
103 raise KeyboardInterrupt
104 if c == '\b':
105 pw = pw[:-1]
106 else:
107 pw = pw + c
Christian Heimes0ec88b32007-12-10 17:02:00 +0000108 msvcrt.putwch('\r')
109 msvcrt.putwch('\n')
Tim Peters07e99cb2001-01-14 23:47:14 +0000110 return pw
Guido van Rossumb5903ac1998-04-09 20:37:16 +0000111
112
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000113def fallback_getpass(prompt='Password: ', stream=None):
114 warnings.warn("Can not control echo on the terminal.", GetPassWarning,
115 stacklevel=2)
116 if not stream:
117 stream = sys.stderr
118 print("Warning: Password input may be echoed.", file=stream)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000119 return _raw_input(prompt, stream)
Guido van Rossum1a7bab01998-07-28 19:28:43 +0000120
121
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000122def _raw_input(prompt="", stream=None, input=None):
Neal Norwitzce96f692006-03-17 06:49:51 +0000123 # This doesn't save the string in the GNU readline history.
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000124 if not stream:
125 stream = sys.stderr
126 if not input:
127 input = sys.stdin
Tim Peters07e99cb2001-01-14 23:47:14 +0000128 prompt = str(prompt)
129 if prompt:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000130 stream.write(prompt)
Guido van Rossumcfb83332008-01-01 16:30:47 +0000131 stream.flush()
Gregory P. Smith50467882009-11-01 18:42:17 +0000132 # NOTE: The Python C API calls flockfile() (and unlock) during readline.
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000133 line = input.readline()
Tim Peters07e99cb2001-01-14 23:47:14 +0000134 if not line:
135 raise EOFError
136 if line[-1] == '\n':
137 line = line[:-1]
138 return line
Guido van Rossumfb9b7fd1998-04-13 20:22:21 +0000139
140
Guido van Rossumb5903ac1998-04-09 20:37:16 +0000141def getuser():
Tim Peters07e99cb2001-01-14 23:47:14 +0000142 """Get the username from the environment or password database.
Guido van Rossumb5903ac1998-04-09 20:37:16 +0000143
Tim Peters07e99cb2001-01-14 23:47:14 +0000144 First try various environment variables, then the password
145 database. This works on Windows as long as USERNAME is set.
Guido van Rossumb5903ac1998-04-09 20:37:16 +0000146
Tim Peters07e99cb2001-01-14 23:47:14 +0000147 """
Guido van Rossumb5903ac1998-04-09 20:37:16 +0000148
Tim Peters07e99cb2001-01-14 23:47:14 +0000149 for name in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'):
150 user = os.environ.get(name)
151 if user:
152 return user
Guido van Rossumb5903ac1998-04-09 20:37:16 +0000153
Tim Peters07e99cb2001-01-14 23:47:14 +0000154 # If this fails, the exception will "explain" why
155 import pwd
156 return pwd.getpwuid(os.getuid())[0]
Jeremy Hylton88d23301999-10-18 22:25:22 +0000157
158# Bind the name getpass to the appropriate function
159try:
Fred Drake1191d012001-02-27 21:23:31 +0000160 import termios
Neal Norwitz201626e2002-11-20 23:15:54 +0000161 # it's possible there is an incompatible termios from the
162 # McMillan Installer, make sure we have a UNIX-compatible termios
163 termios.tcgetattr, termios.tcsetattr
164except (ImportError, AttributeError):
Tim Peters07e99cb2001-01-14 23:47:14 +0000165 try:
166 import msvcrt
Brett Cannoncd171c82013-07-04 17:43:24 -0400167 except ImportError:
Brian Curtinff47a132010-12-16 03:24:49 +0000168 getpass = fallback_getpass
Tim Peters07e99cb2001-01-14 23:47:14 +0000169 else:
170 getpass = win_getpass
Jeremy Hylton88d23301999-10-18 22:25:22 +0000171else:
Tim Peters07e99cb2001-01-14 23:47:14 +0000172 getpass = unix_getpass