|
1 """Utilities to get a password and/or the current user name. |
|
2 |
|
3 getpass(prompt[, stream]) - Prompt for a password, with echo turned off. |
|
4 getuser() - Get the user name from the environment or password database. |
|
5 |
|
6 GetPassWarning - This UserWarning is issued when getpass() cannot prevent |
|
7 echoing of the password contents while reading. |
|
8 |
|
9 On Windows, the msvcrt module will be used. |
|
10 On the Mac EasyDialogs.AskPassword is used, if available. |
|
11 |
|
12 """ |
|
13 |
|
14 # Authors: Piers Lauder (original) |
|
15 # Guido van Rossum (Windows support and cleanup) |
|
16 # Gregory P. Smith (tty support & GetPassWarning) |
|
17 |
|
18 import os, sys, warnings |
|
19 |
|
20 __all__ = ["getpass","getuser","GetPassWarning"] |
|
21 |
|
22 |
|
23 class GetPassWarning(UserWarning): pass |
|
24 |
|
25 |
|
26 def unix_getpass(prompt='Password: ', stream=None): |
|
27 """Prompt for a password, with echo turned off. |
|
28 |
|
29 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. |
|
40 """ |
|
41 fd = None |
|
42 tty = None |
|
43 try: |
|
44 # 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, e: |
|
51 # If that fails, see if stdin can be controlled. |
|
52 try: |
|
53 fd = sys.stdin.fileno() |
|
54 except: |
|
55 passwd = fallback_getpass(prompt, stream) |
|
56 input = sys.stdin |
|
57 if not stream: |
|
58 stream = sys.stderr |
|
59 |
|
60 if fd is not None: |
|
61 passwd = None |
|
62 try: |
|
63 old = termios.tcgetattr(fd) # a copy to save |
|
64 new = old[:] |
|
65 new[3] &= ~termios.ECHO # 3 == 'lflags' |
|
66 try: |
|
67 termios.tcsetattr(fd, termios.TCSADRAIN, new) |
|
68 passwd = _raw_input(prompt, stream, input=input) |
|
69 finally: |
|
70 termios.tcsetattr(fd, termios.TCSADRAIN, old) |
|
71 except termios.error, e: |
|
72 if passwd is not None: |
|
73 # _raw_input succeeded. The final tcsetattr failed. Reraise |
|
74 # instead of leaving the terminal in an unknown state. |
|
75 raise |
|
76 # We can't control the tty or stdin. Give up and use normal IO. |
|
77 # fallback_getpass() raises an appropriate warning. |
|
78 del input, tty # clean up unused file objects before blocking |
|
79 passwd = fallback_getpass(prompt, stream) |
|
80 |
|
81 stream.write('\n') |
|
82 return passwd |
|
83 |
|
84 |
|
85 def win_getpass(prompt='Password: ', stream=None): |
|
86 """Prompt for password with echo off, using Windows getch().""" |
|
87 if sys.stdin is not sys.__stdin__: |
|
88 return fallback_getpass(prompt, stream) |
|
89 import msvcrt |
|
90 for c in prompt: |
|
91 msvcrt.putch(c) |
|
92 pw = "" |
|
93 while 1: |
|
94 c = msvcrt.getch() |
|
95 if c == '\r' or c == '\n': |
|
96 break |
|
97 if c == '\003': |
|
98 raise KeyboardInterrupt |
|
99 if c == '\b': |
|
100 pw = pw[:-1] |
|
101 else: |
|
102 pw = pw + c |
|
103 msvcrt.putch('\r') |
|
104 msvcrt.putch('\n') |
|
105 return pw |
|
106 |
|
107 |
|
108 def fallback_getpass(prompt='Password: ', stream=None): |
|
109 warnings.warn("Can not control echo on the terminal.", GetPassWarning, |
|
110 stacklevel=2) |
|
111 if not stream: |
|
112 stream = sys.stderr |
|
113 print >>stream, "Warning: Password input may be echoed." |
|
114 return _raw_input(prompt, stream) |
|
115 |
|
116 |
|
117 def _raw_input(prompt="", stream=None, input=None): |
|
118 # A raw_input() replacement that doesn't save the string in the |
|
119 # GNU readline history. |
|
120 if not stream: |
|
121 stream = sys.stderr |
|
122 if not input: |
|
123 input = sys.stdin |
|
124 prompt = str(prompt) |
|
125 if prompt: |
|
126 stream.write(prompt) |
|
127 stream.flush() |
|
128 line = input.readline() |
|
129 if not line: |
|
130 raise EOFError |
|
131 if line[-1] == '\n': |
|
132 line = line[:-1] |
|
133 return line |
|
134 |
|
135 |
|
136 def getuser(): |
|
137 """Get the username from the environment or password database. |
|
138 |
|
139 First try various environment variables, then the password |
|
140 database. This works on Windows as long as USERNAME is set. |
|
141 |
|
142 """ |
|
143 |
|
144 import os |
|
145 |
|
146 for name in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'): |
|
147 user = os.environ.get(name) |
|
148 if user: |
|
149 return user |
|
150 |
|
151 # If this fails, the exception will "explain" why |
|
152 import pwd |
|
153 return pwd.getpwuid(os.getuid())[0] |
|
154 |
|
155 # Bind the name getpass to the appropriate function |
|
156 try: |
|
157 import termios |
|
158 # it's possible there is an incompatible termios from the |
|
159 # McMillan Installer, make sure we have a UNIX-compatible termios |
|
160 termios.tcgetattr, termios.tcsetattr |
|
161 except (ImportError, AttributeError): |
|
162 try: |
|
163 import msvcrt |
|
164 except ImportError: |
|
165 try: |
|
166 from EasyDialogs import AskPassword |
|
167 except ImportError: |
|
168 getpass = fallback_getpass |
|
169 else: |
|
170 getpass = AskPassword |
|
171 else: |
|
172 getpass = win_getpass |
|
173 else: |
|
174 getpass = unix_getpass |