xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/getpass.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker"""Utilities to get a password and/or the current user name.
2*cda5da8dSAndroid Build Coastguard Worker
3*cda5da8dSAndroid Build Coastguard Workergetpass(prompt[, stream]) - Prompt for a password, with echo turned off.
4*cda5da8dSAndroid Build Coastguard Workergetuser() - Get the user name from the environment or password database.
5*cda5da8dSAndroid Build Coastguard Worker
6*cda5da8dSAndroid Build Coastguard WorkerGetPassWarning - This UserWarning is issued when getpass() cannot prevent
7*cda5da8dSAndroid Build Coastguard Worker                 echoing of the password contents while reading.
8*cda5da8dSAndroid Build Coastguard Worker
9*cda5da8dSAndroid Build Coastguard WorkerOn Windows, the msvcrt module will be used.
10*cda5da8dSAndroid Build Coastguard Worker
11*cda5da8dSAndroid Build Coastguard Worker"""
12*cda5da8dSAndroid Build Coastguard Worker
13*cda5da8dSAndroid Build Coastguard Worker# Authors: Piers Lauder (original)
14*cda5da8dSAndroid Build Coastguard Worker#          Guido van Rossum (Windows support and cleanup)
15*cda5da8dSAndroid Build Coastguard Worker#          Gregory P. Smith (tty support & GetPassWarning)
16*cda5da8dSAndroid Build Coastguard Worker
17*cda5da8dSAndroid Build Coastguard Workerimport contextlib
18*cda5da8dSAndroid Build Coastguard Workerimport io
19*cda5da8dSAndroid Build Coastguard Workerimport os
20*cda5da8dSAndroid Build Coastguard Workerimport sys
21*cda5da8dSAndroid Build Coastguard Workerimport warnings
22*cda5da8dSAndroid Build Coastguard Worker
23*cda5da8dSAndroid Build Coastguard Worker__all__ = ["getpass","getuser","GetPassWarning"]
24*cda5da8dSAndroid Build Coastguard Worker
25*cda5da8dSAndroid Build Coastguard Worker
26*cda5da8dSAndroid Build Coastguard Workerclass GetPassWarning(UserWarning): pass
27*cda5da8dSAndroid Build Coastguard Worker
28*cda5da8dSAndroid Build Coastguard Worker
29*cda5da8dSAndroid Build Coastguard Workerdef unix_getpass(prompt='Password: ', stream=None):
30*cda5da8dSAndroid Build Coastguard Worker    """Prompt for a password, with echo turned off.
31*cda5da8dSAndroid Build Coastguard Worker
32*cda5da8dSAndroid Build Coastguard Worker    Args:
33*cda5da8dSAndroid Build Coastguard Worker      prompt: Written on stream to ask for the input.  Default: 'Password: '
34*cda5da8dSAndroid Build Coastguard Worker      stream: A writable file object to display the prompt.  Defaults to
35*cda5da8dSAndroid Build Coastguard Worker              the tty.  If no tty is available defaults to sys.stderr.
36*cda5da8dSAndroid Build Coastguard Worker    Returns:
37*cda5da8dSAndroid Build Coastguard Worker      The seKr3t input.
38*cda5da8dSAndroid Build Coastguard Worker    Raises:
39*cda5da8dSAndroid Build Coastguard Worker      EOFError: If our input tty or stdin was closed.
40*cda5da8dSAndroid Build Coastguard Worker      GetPassWarning: When we were unable to turn echo off on the input.
41*cda5da8dSAndroid Build Coastguard Worker
42*cda5da8dSAndroid Build Coastguard Worker    Always restores terminal settings before returning.
43*cda5da8dSAndroid Build Coastguard Worker    """
44*cda5da8dSAndroid Build Coastguard Worker    passwd = None
45*cda5da8dSAndroid Build Coastguard Worker    with contextlib.ExitStack() as stack:
46*cda5da8dSAndroid Build Coastguard Worker        try:
47*cda5da8dSAndroid Build Coastguard Worker            # Always try reading and writing directly on the tty first.
48*cda5da8dSAndroid Build Coastguard Worker            fd = os.open('/dev/tty', os.O_RDWR|os.O_NOCTTY)
49*cda5da8dSAndroid Build Coastguard Worker            tty = io.FileIO(fd, 'w+')
50*cda5da8dSAndroid Build Coastguard Worker            stack.enter_context(tty)
51*cda5da8dSAndroid Build Coastguard Worker            input = io.TextIOWrapper(tty)
52*cda5da8dSAndroid Build Coastguard Worker            stack.enter_context(input)
53*cda5da8dSAndroid Build Coastguard Worker            if not stream:
54*cda5da8dSAndroid Build Coastguard Worker                stream = input
55*cda5da8dSAndroid Build Coastguard Worker        except OSError:
56*cda5da8dSAndroid Build Coastguard Worker            # If that fails, see if stdin can be controlled.
57*cda5da8dSAndroid Build Coastguard Worker            stack.close()
58*cda5da8dSAndroid Build Coastguard Worker            try:
59*cda5da8dSAndroid Build Coastguard Worker                fd = sys.stdin.fileno()
60*cda5da8dSAndroid Build Coastguard Worker            except (AttributeError, ValueError):
61*cda5da8dSAndroid Build Coastguard Worker                fd = None
62*cda5da8dSAndroid Build Coastguard Worker                passwd = fallback_getpass(prompt, stream)
63*cda5da8dSAndroid Build Coastguard Worker            input = sys.stdin
64*cda5da8dSAndroid Build Coastguard Worker            if not stream:
65*cda5da8dSAndroid Build Coastguard Worker                stream = sys.stderr
66*cda5da8dSAndroid Build Coastguard Worker
67*cda5da8dSAndroid Build Coastguard Worker        if fd is not None:
68*cda5da8dSAndroid Build Coastguard Worker            try:
69*cda5da8dSAndroid Build Coastguard Worker                old = termios.tcgetattr(fd)     # a copy to save
70*cda5da8dSAndroid Build Coastguard Worker                new = old[:]
71*cda5da8dSAndroid Build Coastguard Worker                new[3] &= ~termios.ECHO  # 3 == 'lflags'
72*cda5da8dSAndroid Build Coastguard Worker                tcsetattr_flags = termios.TCSAFLUSH
73*cda5da8dSAndroid Build Coastguard Worker                if hasattr(termios, 'TCSASOFT'):
74*cda5da8dSAndroid Build Coastguard Worker                    tcsetattr_flags |= termios.TCSASOFT
75*cda5da8dSAndroid Build Coastguard Worker                try:
76*cda5da8dSAndroid Build Coastguard Worker                    termios.tcsetattr(fd, tcsetattr_flags, new)
77*cda5da8dSAndroid Build Coastguard Worker                    passwd = _raw_input(prompt, stream, input=input)
78*cda5da8dSAndroid Build Coastguard Worker                finally:
79*cda5da8dSAndroid Build Coastguard Worker                    termios.tcsetattr(fd, tcsetattr_flags, old)
80*cda5da8dSAndroid Build Coastguard Worker                    stream.flush()  # issue7208
81*cda5da8dSAndroid Build Coastguard Worker            except termios.error:
82*cda5da8dSAndroid Build Coastguard Worker                if passwd is not None:
83*cda5da8dSAndroid Build Coastguard Worker                    # _raw_input succeeded.  The final tcsetattr failed.  Reraise
84*cda5da8dSAndroid Build Coastguard Worker                    # instead of leaving the terminal in an unknown state.
85*cda5da8dSAndroid Build Coastguard Worker                    raise
86*cda5da8dSAndroid Build Coastguard Worker                # We can't control the tty or stdin.  Give up and use normal IO.
87*cda5da8dSAndroid Build Coastguard Worker                # fallback_getpass() raises an appropriate warning.
88*cda5da8dSAndroid Build Coastguard Worker                if stream is not input:
89*cda5da8dSAndroid Build Coastguard Worker                    # clean up unused file objects before blocking
90*cda5da8dSAndroid Build Coastguard Worker                    stack.close()
91*cda5da8dSAndroid Build Coastguard Worker                passwd = fallback_getpass(prompt, stream)
92*cda5da8dSAndroid Build Coastguard Worker
93*cda5da8dSAndroid Build Coastguard Worker        stream.write('\n')
94*cda5da8dSAndroid Build Coastguard Worker        return passwd
95*cda5da8dSAndroid Build Coastguard Worker
96*cda5da8dSAndroid Build Coastguard Worker
97*cda5da8dSAndroid Build Coastguard Workerdef win_getpass(prompt='Password: ', stream=None):
98*cda5da8dSAndroid Build Coastguard Worker    """Prompt for password with echo off, using Windows getwch()."""
99*cda5da8dSAndroid Build Coastguard Worker    if sys.stdin is not sys.__stdin__:
100*cda5da8dSAndroid Build Coastguard Worker        return fallback_getpass(prompt, stream)
101*cda5da8dSAndroid Build Coastguard Worker
102*cda5da8dSAndroid Build Coastguard Worker    for c in prompt:
103*cda5da8dSAndroid Build Coastguard Worker        msvcrt.putwch(c)
104*cda5da8dSAndroid Build Coastguard Worker    pw = ""
105*cda5da8dSAndroid Build Coastguard Worker    while 1:
106*cda5da8dSAndroid Build Coastguard Worker        c = msvcrt.getwch()
107*cda5da8dSAndroid Build Coastguard Worker        if c == '\r' or c == '\n':
108*cda5da8dSAndroid Build Coastguard Worker            break
109*cda5da8dSAndroid Build Coastguard Worker        if c == '\003':
110*cda5da8dSAndroid Build Coastguard Worker            raise KeyboardInterrupt
111*cda5da8dSAndroid Build Coastguard Worker        if c == '\b':
112*cda5da8dSAndroid Build Coastguard Worker            pw = pw[:-1]
113*cda5da8dSAndroid Build Coastguard Worker        else:
114*cda5da8dSAndroid Build Coastguard Worker            pw = pw + c
115*cda5da8dSAndroid Build Coastguard Worker    msvcrt.putwch('\r')
116*cda5da8dSAndroid Build Coastguard Worker    msvcrt.putwch('\n')
117*cda5da8dSAndroid Build Coastguard Worker    return pw
118*cda5da8dSAndroid Build Coastguard Worker
119*cda5da8dSAndroid Build Coastguard Worker
120*cda5da8dSAndroid Build Coastguard Workerdef fallback_getpass(prompt='Password: ', stream=None):
121*cda5da8dSAndroid Build Coastguard Worker    warnings.warn("Can not control echo on the terminal.", GetPassWarning,
122*cda5da8dSAndroid Build Coastguard Worker                  stacklevel=2)
123*cda5da8dSAndroid Build Coastguard Worker    if not stream:
124*cda5da8dSAndroid Build Coastguard Worker        stream = sys.stderr
125*cda5da8dSAndroid Build Coastguard Worker    print("Warning: Password input may be echoed.", file=stream)
126*cda5da8dSAndroid Build Coastguard Worker    return _raw_input(prompt, stream)
127*cda5da8dSAndroid Build Coastguard Worker
128*cda5da8dSAndroid Build Coastguard Worker
129*cda5da8dSAndroid Build Coastguard Workerdef _raw_input(prompt="", stream=None, input=None):
130*cda5da8dSAndroid Build Coastguard Worker    # This doesn't save the string in the GNU readline history.
131*cda5da8dSAndroid Build Coastguard Worker    if not stream:
132*cda5da8dSAndroid Build Coastguard Worker        stream = sys.stderr
133*cda5da8dSAndroid Build Coastguard Worker    if not input:
134*cda5da8dSAndroid Build Coastguard Worker        input = sys.stdin
135*cda5da8dSAndroid Build Coastguard Worker    prompt = str(prompt)
136*cda5da8dSAndroid Build Coastguard Worker    if prompt:
137*cda5da8dSAndroid Build Coastguard Worker        try:
138*cda5da8dSAndroid Build Coastguard Worker            stream.write(prompt)
139*cda5da8dSAndroid Build Coastguard Worker        except UnicodeEncodeError:
140*cda5da8dSAndroid Build Coastguard Worker            # Use replace error handler to get as much as possible printed.
141*cda5da8dSAndroid Build Coastguard Worker            prompt = prompt.encode(stream.encoding, 'replace')
142*cda5da8dSAndroid Build Coastguard Worker            prompt = prompt.decode(stream.encoding)
143*cda5da8dSAndroid Build Coastguard Worker            stream.write(prompt)
144*cda5da8dSAndroid Build Coastguard Worker        stream.flush()
145*cda5da8dSAndroid Build Coastguard Worker    # NOTE: The Python C API calls flockfile() (and unlock) during readline.
146*cda5da8dSAndroid Build Coastguard Worker    line = input.readline()
147*cda5da8dSAndroid Build Coastguard Worker    if not line:
148*cda5da8dSAndroid Build Coastguard Worker        raise EOFError
149*cda5da8dSAndroid Build Coastguard Worker    if line[-1] == '\n':
150*cda5da8dSAndroid Build Coastguard Worker        line = line[:-1]
151*cda5da8dSAndroid Build Coastguard Worker    return line
152*cda5da8dSAndroid Build Coastguard Worker
153*cda5da8dSAndroid Build Coastguard Worker
154*cda5da8dSAndroid Build Coastguard Workerdef getuser():
155*cda5da8dSAndroid Build Coastguard Worker    """Get the username from the environment or password database.
156*cda5da8dSAndroid Build Coastguard Worker
157*cda5da8dSAndroid Build Coastguard Worker    First try various environment variables, then the password
158*cda5da8dSAndroid Build Coastguard Worker    database.  This works on Windows as long as USERNAME is set.
159*cda5da8dSAndroid Build Coastguard Worker
160*cda5da8dSAndroid Build Coastguard Worker    """
161*cda5da8dSAndroid Build Coastguard Worker
162*cda5da8dSAndroid Build Coastguard Worker    for name in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'):
163*cda5da8dSAndroid Build Coastguard Worker        user = os.environ.get(name)
164*cda5da8dSAndroid Build Coastguard Worker        if user:
165*cda5da8dSAndroid Build Coastguard Worker            return user
166*cda5da8dSAndroid Build Coastguard Worker
167*cda5da8dSAndroid Build Coastguard Worker    # If this fails, the exception will "explain" why
168*cda5da8dSAndroid Build Coastguard Worker    import pwd
169*cda5da8dSAndroid Build Coastguard Worker    return pwd.getpwuid(os.getuid())[0]
170*cda5da8dSAndroid Build Coastguard Worker
171*cda5da8dSAndroid Build Coastguard Worker# Bind the name getpass to the appropriate function
172*cda5da8dSAndroid Build Coastguard Workertry:
173*cda5da8dSAndroid Build Coastguard Worker    import termios
174*cda5da8dSAndroid Build Coastguard Worker    # it's possible there is an incompatible termios from the
175*cda5da8dSAndroid Build Coastguard Worker    # McMillan Installer, make sure we have a UNIX-compatible termios
176*cda5da8dSAndroid Build Coastguard Worker    termios.tcgetattr, termios.tcsetattr
177*cda5da8dSAndroid Build Coastguard Workerexcept (ImportError, AttributeError):
178*cda5da8dSAndroid Build Coastguard Worker    try:
179*cda5da8dSAndroid Build Coastguard Worker        import msvcrt
180*cda5da8dSAndroid Build Coastguard Worker    except ImportError:
181*cda5da8dSAndroid Build Coastguard Worker        getpass = fallback_getpass
182*cda5da8dSAndroid Build Coastguard Worker    else:
183*cda5da8dSAndroid Build Coastguard Worker        getpass = win_getpass
184*cda5da8dSAndroid Build Coastguard Workerelse:
185*cda5da8dSAndroid Build Coastguard Worker    getpass = unix_getpass
186