blob: 2eb01fac3daf03c44cde5767b7af832609ea4970 [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
Tim Peters07e99cb2001-01-14 23:47:14 +000043 try:
Christian Heimes81ee3ef2008-05-04 22:42:01 +000044 # Always try reading and writing directly on the tty first.
45 fd = os.open('/dev/tty', os.O_RDWR|os.O_NOCTTY)
46 tty = os.fdopen(fd, 'w+', 1)
47 input = tty
48 if not stream:
49 stream = tty
50 except EnvironmentError as e:
51 # If that fails, see if stdin can be controlled.
52 try:
53 fd = sys.stdin.fileno()
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +000054 except (AttributeError, ValueError):
Christian Heimes81ee3ef2008-05-04 22:42:01 +000055 passwd = fallback_getpass(prompt, stream)
56 input = sys.stdin
57 if not stream:
58 stream = sys.stderr
Guido van Rossumb5903ac1998-04-09 20:37:16 +000059
Christian Heimes81ee3ef2008-05-04 22:42:01 +000060 if fd is not None:
61 passwd = None
62 try:
63 old = termios.tcgetattr(fd) # a copy to save
64 new = old[:]
Gregory P. Smith50467882009-11-01 18:42:17 +000065 new[3] &= ~(termios.ECHO|termios.ISIG) # 3 == 'lflags'
66 tcsetattr_flags = termios.TCSAFLUSH
67 if hasattr(termios, 'TCSASOFT'):
68 tcsetattr_flags |= termios.TCSASOFT
Christian Heimes81ee3ef2008-05-04 22:42:01 +000069 try:
Gregory P. Smith50467882009-11-01 18:42:17 +000070 termios.tcsetattr(fd, tcsetattr_flags, new)
Christian Heimes81ee3ef2008-05-04 22:42:01 +000071 passwd = _raw_input(prompt, stream, input=input)
72 finally:
Gregory P. Smith50467882009-11-01 18:42:17 +000073 termios.tcsetattr(fd, tcsetattr_flags, old)
74 stream.flush() # issue7208
Christian Heimes81ee3ef2008-05-04 22:42:01 +000075 except termios.error as e:
76 if passwd is not None:
77 # _raw_input succeeded. The final tcsetattr failed. Reraise
78 # instead of leaving the terminal in an unknown state.
79 raise
80 # We can't control the tty or stdin. Give up and use normal IO.
81 # fallback_getpass() raises an appropriate warning.
82 del input, tty # clean up unused file objects before blocking
83 passwd = fallback_getpass(prompt, stream)
Guido van Rossumb5903ac1998-04-09 20:37:16 +000084
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000085 stream.write('\n')
Tim Peters07e99cb2001-01-14 23:47:14 +000086 return passwd
Guido van Rossumb5903ac1998-04-09 20:37:16 +000087
88
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000089def win_getpass(prompt='Password: ', stream=None):
Tim Peters07e99cb2001-01-14 23:47:14 +000090 """Prompt for password with echo off, using Windows getch()."""
Guido van Rossum60250e22001-08-30 15:07:44 +000091 if sys.stdin is not sys.__stdin__:
Christian Heimes81ee3ef2008-05-04 22:42:01 +000092 return fallback_getpass(prompt, stream)
Tim Peters07e99cb2001-01-14 23:47:14 +000093 import msvcrt
94 for c in prompt:
Christian Heimes0ec88b32007-12-10 17:02:00 +000095 msvcrt.putwch(c)
Tim Peters07e99cb2001-01-14 23:47:14 +000096 pw = ""
97 while 1:
Christian Heimes0ec88b32007-12-10 17:02:00 +000098 c = msvcrt.getwch()
Tim Peters07e99cb2001-01-14 23:47:14 +000099 if c == '\r' or c == '\n':
100 break
101 if c == '\003':
102 raise KeyboardInterrupt
103 if c == '\b':
104 pw = pw[:-1]
105 else:
106 pw = pw + c
Christian Heimes0ec88b32007-12-10 17:02:00 +0000107 msvcrt.putwch('\r')
108 msvcrt.putwch('\n')
Tim Peters07e99cb2001-01-14 23:47:14 +0000109 return pw
Guido van Rossumb5903ac1998-04-09 20:37:16 +0000110
111
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000112def fallback_getpass(prompt='Password: ', stream=None):
113 warnings.warn("Can not control echo on the terminal.", GetPassWarning,
114 stacklevel=2)
115 if not stream:
116 stream = sys.stderr
117 print("Warning: Password input may be echoed.", file=stream)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000118 return _raw_input(prompt, stream)
Guido van Rossum1a7bab01998-07-28 19:28:43 +0000119
120
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000121def _raw_input(prompt="", stream=None, input=None):
Neal Norwitzce96f692006-03-17 06:49:51 +0000122 # This doesn't save the string in the GNU readline history.
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000123 if not stream:
124 stream = sys.stderr
125 if not input:
126 input = sys.stdin
Tim Peters07e99cb2001-01-14 23:47:14 +0000127 prompt = str(prompt)
128 if prompt:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000129 stream.write(prompt)
Guido van Rossumcfb83332008-01-01 16:30:47 +0000130 stream.flush()
Gregory P. Smith50467882009-11-01 18:42:17 +0000131 # NOTE: The Python C API calls flockfile() (and unlock) during readline.
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000132 line = input.readline()
Tim Peters07e99cb2001-01-14 23:47:14 +0000133 if not line:
134 raise EOFError
135 if line[-1] == '\n':
136 line = line[:-1]
137 return line
Guido van Rossumfb9b7fd1998-04-13 20:22:21 +0000138
139
Guido van Rossumb5903ac1998-04-09 20:37:16 +0000140def getuser():
Tim Peters07e99cb2001-01-14 23:47:14 +0000141 """Get the username from the environment or password database.
Guido van Rossumb5903ac1998-04-09 20:37:16 +0000142
Tim Peters07e99cb2001-01-14 23:47:14 +0000143 First try various environment variables, then the password
144 database. This works on Windows as long as USERNAME is set.
Guido van Rossumb5903ac1998-04-09 20:37:16 +0000145
Tim Peters07e99cb2001-01-14 23:47:14 +0000146 """
Guido van Rossumb5903ac1998-04-09 20:37:16 +0000147
Tim Peters07e99cb2001-01-14 23:47:14 +0000148 import os
Guido van Rossumb5903ac1998-04-09 20:37:16 +0000149
Tim Peters07e99cb2001-01-14 23:47:14 +0000150 for name in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'):
151 user = os.environ.get(name)
152 if user:
153 return user
Guido van Rossumb5903ac1998-04-09 20:37:16 +0000154
Tim Peters07e99cb2001-01-14 23:47:14 +0000155 # If this fails, the exception will "explain" why
156 import pwd
157 return pwd.getpwuid(os.getuid())[0]
Jeremy Hylton88d23301999-10-18 22:25:22 +0000158
159# Bind the name getpass to the appropriate function
160try:
Fred Drake1191d012001-02-27 21:23:31 +0000161 import termios
Neal Norwitz201626e2002-11-20 23:15:54 +0000162 # it's possible there is an incompatible termios from the
163 # McMillan Installer, make sure we have a UNIX-compatible termios
164 termios.tcgetattr, termios.tcsetattr
165except (ImportError, AttributeError):
Tim Peters07e99cb2001-01-14 23:47:14 +0000166 try:
167 import msvcrt
168 except ImportError:
169 try:
170 from EasyDialogs import AskPassword
171 except ImportError:
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000172 getpass = fallback_getpass
Tim Peters07e99cb2001-01-14 23:47:14 +0000173 else:
174 getpass = AskPassword
175 else:
176 getpass = win_getpass
Jeremy Hylton88d23301999-10-18 22:25:22 +0000177else:
Tim Peters07e99cb2001-01-14 23:47:14 +0000178 getpass = unix_getpass