blob: 36e17e4cb6965db548f445e8e9f156da27d2109b [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.
Jeremy Hylton88d23301999-10-18 22:25:22 +000010
Guido van Rossumb5903ac1998-04-09 20:37:16 +000011"""
12
Guido van Rossum98d9fd32000-02-28 15:12:25 +000013# Authors: Piers Lauder (original)
14# Guido van Rossum (Windows support and cleanup)
Christian Heimes81ee3ef2008-05-04 22:42:01 +000015# Gregory P. Smith (tty support & GetPassWarning)
Guido van Rossum98d9fd32000-02-28 15:12:25 +000016
R David Murray16dbbae2013-07-10 17:02:24 -040017import contextlib
18import io
19import os
20import sys
21import warnings
Guido van Rossumb5903ac1998-04-09 20:37:16 +000022
Christian Heimes81ee3ef2008-05-04 22:42:01 +000023__all__ = ["getpass","getuser","GetPassWarning"]
24
25
26class GetPassWarning(UserWarning): pass
27
Skip Montanaroeccd02a2001-01-20 23:34:12 +000028
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000029def unix_getpass(prompt='Password: ', stream=None):
Tim Peters07e99cb2001-01-14 23:47:14 +000030 """Prompt for a password, with echo turned off.
Guido van Rossumb5903ac1998-04-09 20:37:16 +000031
Christian Heimes81ee3ef2008-05-04 22:42:01 +000032 Args:
33 prompt: Written on stream to ask for the input. Default: 'Password: '
34 stream: A writable file object to display the prompt. Defaults to
35 the tty. If no tty is available defaults to sys.stderr.
36 Returns:
37 The seKr3t input.
38 Raises:
39 EOFError: If our input tty or stdin was closed.
40 GetPassWarning: When we were unable to turn echo off on the input.
41
42 Always restores terminal settings before returning.
Tim Peters07e99cb2001-01-14 23:47:14 +000043 """
R David Murray319d58d2013-04-08 01:48:22 -040044 passwd = None
R David Murray16dbbae2013-07-10 17:02:24 -040045 with contextlib.ExitStack() as stack:
Christian Heimes81ee3ef2008-05-04 22:42:01 +000046 try:
R David Murray16dbbae2013-07-10 17:02:24 -040047 # Always try reading and writing directly on the tty first.
48 fd = os.open('/dev/tty', os.O_RDWR|os.O_NOCTTY)
49 tty = io.FileIO(fd, 'w+')
50 stack.enter_context(tty)
51 input = io.TextIOWrapper(tty)
52 stack.enter_context(input)
53 if not stream:
54 stream = input
55 except OSError as e:
56 # If that fails, see if stdin can be controlled.
57 stack.close()
Christian Heimes81ee3ef2008-05-04 22:42:01 +000058 try:
R David Murray16dbbae2013-07-10 17:02:24 -040059 fd = sys.stdin.fileno()
60 except (AttributeError, ValueError):
61 fd = None
62 passwd = fallback_getpass(prompt, stream)
63 input = sys.stdin
64 if not stream:
65 stream = sys.stderr
Guido van Rossumb5903ac1998-04-09 20:37:16 +000066
R David Murray16dbbae2013-07-10 17:02:24 -040067 if fd is not None:
68 try:
69 old = termios.tcgetattr(fd) # a copy to save
70 new = old[:]
71 new[3] &= ~termios.ECHO # 3 == 'lflags'
72 tcsetattr_flags = termios.TCSAFLUSH
73 if hasattr(termios, 'TCSASOFT'):
74 tcsetattr_flags |= termios.TCSASOFT
75 try:
76 termios.tcsetattr(fd, tcsetattr_flags, new)
77 passwd = _raw_input(prompt, stream, input=input)
78 finally:
79 termios.tcsetattr(fd, tcsetattr_flags, old)
80 stream.flush() # issue7208
81 except termios.error:
82 if passwd is not None:
83 # _raw_input succeeded. The final tcsetattr failed. Reraise
84 # instead of leaving the terminal in an unknown state.
85 raise
86 # We can't control the tty or stdin. Give up and use normal IO.
87 # fallback_getpass() raises an appropriate warning.
88 if stream is not input:
89 # clean up unused file objects before blocking
90 stack.close()
91 passwd = fallback_getpass(prompt, stream)
92
93 stream.write('\n')
94 return passwd
Guido van Rossumb5903ac1998-04-09 20:37:16 +000095
96
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000097def win_getpass(prompt='Password: ', stream=None):
Tim Peters07e99cb2001-01-14 23:47:14 +000098 """Prompt for password with echo off, using Windows getch()."""
Guido van Rossum60250e22001-08-30 15:07:44 +000099 if sys.stdin is not sys.__stdin__:
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000100 return fallback_getpass(prompt, stream)
Benjamin Peterson669ff662015-10-28 23:15:13 -0700101
Tim Peters07e99cb2001-01-14 23:47:14 +0000102 for c in prompt:
Christian Heimes0ec88b32007-12-10 17:02:00 +0000103 msvcrt.putwch(c)
Tim Peters07e99cb2001-01-14 23:47:14 +0000104 pw = ""
105 while 1:
Christian Heimes0ec88b32007-12-10 17:02:00 +0000106 c = msvcrt.getwch()
Tim Peters07e99cb2001-01-14 23:47:14 +0000107 if c == '\r' or c == '\n':
108 break
109 if c == '\003':
110 raise KeyboardInterrupt
111 if c == '\b':
112 pw = pw[:-1]
113 else:
114 pw = pw + c
Christian Heimes0ec88b32007-12-10 17:02:00 +0000115 msvcrt.putwch('\r')
116 msvcrt.putwch('\n')
Tim Peters07e99cb2001-01-14 23:47:14 +0000117 return pw
Guido van Rossumb5903ac1998-04-09 20:37:16 +0000118
119
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000120def fallback_getpass(prompt='Password: ', stream=None):
121 warnings.warn("Can not control echo on the terminal.", GetPassWarning,
122 stacklevel=2)
123 if not stream:
124 stream = sys.stderr
125 print("Warning: Password input may be echoed.", file=stream)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000126 return _raw_input(prompt, stream)
Guido van Rossum1a7bab01998-07-28 19:28:43 +0000127
128
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000129def _raw_input(prompt="", stream=None, input=None):
Neal Norwitzce96f692006-03-17 06:49:51 +0000130 # This doesn't save the string in the GNU readline history.
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000131 if not stream:
132 stream = sys.stderr
133 if not input:
134 input = sys.stdin
Tim Peters07e99cb2001-01-14 23:47:14 +0000135 prompt = str(prompt)
136 if prompt:
R David Murrayd5aa4872014-04-13 22:07:39 -0400137 try:
138 stream.write(prompt)
139 except UnicodeEncodeError:
R David Murray604453c2014-04-14 10:28:58 -0400140 # Use replace error handler to get as much as possible printed.
R David Murrayd5aa4872014-04-13 22:07:39 -0400141 prompt = prompt.encode(stream.encoding, 'replace')
142 prompt = prompt.decode(stream.encoding)
143 stream.write(prompt)
Guido van Rossumcfb83332008-01-01 16:30:47 +0000144 stream.flush()
Gregory P. Smith50467882009-11-01 18:42:17 +0000145 # NOTE: The Python C API calls flockfile() (and unlock) during readline.
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000146 line = input.readline()
Tim Peters07e99cb2001-01-14 23:47:14 +0000147 if not line:
148 raise EOFError
149 if line[-1] == '\n':
150 line = line[:-1]
151 return line
Guido van Rossumfb9b7fd1998-04-13 20:22:21 +0000152
153
Guido van Rossumb5903ac1998-04-09 20:37:16 +0000154def getuser():
Tim Peters07e99cb2001-01-14 23:47:14 +0000155 """Get the username from the environment or password database.
Guido van Rossumb5903ac1998-04-09 20:37:16 +0000156
Tim Peters07e99cb2001-01-14 23:47:14 +0000157 First try various environment variables, then the password
158 database. This works on Windows as long as USERNAME is set.
Guido van Rossumb5903ac1998-04-09 20:37:16 +0000159
Tim Peters07e99cb2001-01-14 23:47:14 +0000160 """
Guido van Rossumb5903ac1998-04-09 20:37:16 +0000161
Tim Peters07e99cb2001-01-14 23:47:14 +0000162 for name in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'):
163 user = os.environ.get(name)
164 if user:
165 return user
Guido van Rossumb5903ac1998-04-09 20:37:16 +0000166
Tim Peters07e99cb2001-01-14 23:47:14 +0000167 # If this fails, the exception will "explain" why
168 import pwd
169 return pwd.getpwuid(os.getuid())[0]
Jeremy Hylton88d23301999-10-18 22:25:22 +0000170
171# Bind the name getpass to the appropriate function
172try:
Fred Drake1191d012001-02-27 21:23:31 +0000173 import termios
Neal Norwitz201626e2002-11-20 23:15:54 +0000174 # it's possible there is an incompatible termios from the
175 # McMillan Installer, make sure we have a UNIX-compatible termios
176 termios.tcgetattr, termios.tcsetattr
177except (ImportError, AttributeError):
Tim Peters07e99cb2001-01-14 23:47:14 +0000178 try:
179 import msvcrt
Brett Cannoncd171c82013-07-04 17:43:24 -0400180 except ImportError:
Brian Curtinff47a132010-12-16 03:24:49 +0000181 getpass = fallback_getpass
Tim Peters07e99cb2001-01-14 23:47:14 +0000182 else:
183 getpass = win_getpass
Jeremy Hylton88d23301999-10-18 22:25:22 +0000184else:
Tim Peters07e99cb2001-01-14 23:47:14 +0000185 getpass = unix_getpass