Home | History | Annotate | Download | only in python2.7
      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 (AttributeError, ValueError):
     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             tcsetattr_flags = termios.TCSAFLUSH
     67             if hasattr(termios, 'TCSASOFT'):
     68                 tcsetattr_flags |= termios.TCSASOFT
     69             try:
     70                 termios.tcsetattr(fd, tcsetattr_flags, new)
     71                 passwd = _raw_input(prompt, stream, input=input)
     72             finally:
     73                 termios.tcsetattr(fd, tcsetattr_flags, old)
     74                 stream.flush()  # issue7208
     75         except termios.error, 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)
     84 
     85     stream.write('\n')
     86     return passwd
     87 
     88 
     89 def win_getpass(prompt='Password: ', stream=None):
     90     """Prompt for password with echo off, using Windows getch()."""
     91     if sys.stdin is not sys.__stdin__:
     92         return fallback_getpass(prompt, stream)
     93     import msvcrt
     94     for c in prompt:
     95         msvcrt.putch(c)
     96     pw = ""
     97     while 1:
     98         c = msvcrt.getch()
     99         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
    107     msvcrt.putch('\r')
    108     msvcrt.putch('\n')
    109     return pw
    110 
    111 
    112 def 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 >>stream, "Warning: Password input may be echoed."
    118     return _raw_input(prompt, stream)
    119 
    120 
    121 def _raw_input(prompt="", stream=None, input=None):
    122     # A raw_input() replacement that doesn't save the string in the
    123     # GNU readline history.
    124     if not stream:
    125         stream = sys.stderr
    126     if not input:
    127         input = sys.stdin
    128     prompt = str(prompt)
    129     if prompt:
    130         stream.write(prompt)
    131         stream.flush()
    132     # NOTE: The Python C API calls flockfile() (and unlock) during readline.
    133     line = input.readline()
    134     if not line:
    135         raise EOFError
    136     if line[-1] == '\n':
    137         line = line[:-1]
    138     return line
    139 
    140 
    141 def getuser():
    142     """Get the username from the environment or password database.
    143 
    144     First try various environment variables, then the password
    145     database.  This works on Windows as long as USERNAME is set.
    146 
    147     """
    148 
    149     import os
    150 
    151     for name in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'):
    152         user = os.environ.get(name)
    153         if user:
    154             return user
    155 
    156     # If this fails, the exception will "explain" why
    157     import pwd
    158     return pwd.getpwuid(os.getuid())[0]
    159 
    160 # Bind the name getpass to the appropriate function
    161 try:
    162     import termios
    163     # it's possible there is an incompatible termios from the
    164     # McMillan Installer, make sure we have a UNIX-compatible termios
    165     termios.tcgetattr, termios.tcsetattr
    166 except (ImportError, AttributeError):
    167     try:
    168         import msvcrt
    169     except ImportError:
    170         try:
    171             from EasyDialogs import AskPassword
    172         except ImportError:
    173             getpass = fallback_getpass
    174         else:
    175             getpass = AskPassword
    176     else:
    177         getpass = win_getpass
    178 else:
    179     getpass = unix_getpass
    180