Blame src/gl/getpass.c

Packit Service 991b93
/* Copyright (C) 1992-2001, 2003-2007, 2009-2020 Free Software Foundation, Inc.
Packit aea12f
Packit aea12f
   This file is part of the GNU C Library.
Packit aea12f
Packit aea12f
   This program is free software; you can redistribute it and/or modify
Packit aea12f
   it under the terms of the GNU General Public License as published by
Packit aea12f
   the Free Software Foundation; either version 3, or (at your option)
Packit aea12f
   any later version.
Packit aea12f
Packit aea12f
   This program is distributed in the hope that it will be useful,
Packit aea12f
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit aea12f
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit aea12f
   GNU General Public License for more details.
Packit aea12f
Packit aea12f
   You should have received a copy of the GNU General Public License along
Packit aea12f
   with this program; if not, see <https://www.gnu.org/licenses/>.  */
Packit aea12f
Packit aea12f
#ifndef _LIBC
Packit aea12f
# include <config.h>
Packit aea12f
#endif
Packit aea12f
Packit aea12f
#include "getpass.h"
Packit aea12f
Packit aea12f
#include <stdio.h>
Packit aea12f
Packit aea12f
#if !(defined _WIN32 && !defined __CYGWIN__)
Packit aea12f
Packit aea12f
# include <stdbool.h>
Packit aea12f
Packit aea12f
# if HAVE_DECL___FSETLOCKING && HAVE___FSETLOCKING
Packit aea12f
#  if HAVE_STDIO_EXT_H
Packit aea12f
#   include <stdio_ext.h>
Packit aea12f
#  endif
Packit aea12f
# else
Packit aea12f
#  define __fsetlocking(stream, type)    /* empty */
Packit aea12f
# endif
Packit aea12f
Packit aea12f
# if HAVE_TERMIOS_H
Packit aea12f
#  include <termios.h>
Packit aea12f
# endif
Packit aea12f
Packit aea12f
# if USE_UNLOCKED_IO
Packit aea12f
#  include "unlocked-io.h"
Packit aea12f
# else
Packit aea12f
#  if !HAVE_DECL_FFLUSH_UNLOCKED
Packit aea12f
#   undef fflush_unlocked
Packit aea12f
#   define fflush_unlocked(x) fflush (x)
Packit aea12f
#  endif
Packit aea12f
#  if !HAVE_DECL_FLOCKFILE
Packit aea12f
#   undef flockfile
Packit aea12f
#   define flockfile(x) ((void) 0)
Packit aea12f
#  endif
Packit aea12f
#  if !HAVE_DECL_FUNLOCKFILE
Packit aea12f
#   undef funlockfile
Packit aea12f
#   define funlockfile(x) ((void) 0)
Packit aea12f
#  endif
Packit aea12f
#  if !HAVE_DECL_FPUTS_UNLOCKED
Packit aea12f
#   undef fputs_unlocked
Packit aea12f
#   define fputs_unlocked(str,stream) fputs (str, stream)
Packit aea12f
#  endif
Packit aea12f
#  if !HAVE_DECL_PUTC_UNLOCKED
Packit aea12f
#   undef putc_unlocked
Packit aea12f
#   define putc_unlocked(c,stream) putc (c, stream)
Packit aea12f
#  endif
Packit aea12f
# endif
Packit aea12f
Packit aea12f
/* It is desirable to use this bit on systems that have it.
Packit aea12f
   The only bit of terminal state we want to twiddle is echoing, which is
Packit aea12f
   done in software; there is no need to change the state of the terminal
Packit aea12f
   hardware.  */
Packit aea12f
Packit aea12f
# ifndef TCSASOFT
Packit aea12f
#  define TCSASOFT 0
Packit aea12f
# endif
Packit aea12f
Packit aea12f
static void
Packit aea12f
call_fclose (void *arg)
Packit aea12f
{
Packit aea12f
  if (arg != NULL)
Packit aea12f
    fclose (arg);
Packit aea12f
}
Packit aea12f
Packit aea12f
char *
Packit aea12f
getpass (const char *prompt)
Packit aea12f
{
Packit aea12f
  FILE *tty;
Packit aea12f
  FILE *in, *out;
Packit aea12f
# if HAVE_TCGETATTR
Packit aea12f
  struct termios s, t;
Packit aea12f
# endif
Packit aea12f
  bool tty_changed = false;
Packit aea12f
  static char *buf;
Packit aea12f
  static size_t bufsize;
Packit aea12f
  ssize_t nread;
Packit aea12f
Packit aea12f
  /* Try to write to and read from the terminal if we can.
Packit aea12f
     If we can't open the terminal, use stderr and stdin.  */
Packit aea12f
Packit Service 991b93
  tty = fopen ("/dev/tty", "w+e");
Packit aea12f
  if (tty == NULL)
Packit aea12f
    {
Packit aea12f
      in = stdin;
Packit aea12f
      out = stderr;
Packit aea12f
    }
Packit aea12f
  else
Packit aea12f
    {
Packit aea12f
      /* We do the locking ourselves.  */
Packit aea12f
      __fsetlocking (tty, FSETLOCKING_BYCALLER);
Packit aea12f
Packit aea12f
      out = in = tty;
Packit aea12f
    }
Packit aea12f
Packit aea12f
  flockfile (out);
Packit aea12f
Packit aea12f
  /* Turn echoing off if it is on now.  */
Packit aea12f
# if HAVE_TCGETATTR
Packit aea12f
  if (tcgetattr (fileno (in), &t) == 0)
Packit aea12f
    {
Packit aea12f
      /* Save the old one. */
Packit aea12f
      s = t;
Packit aea12f
      /* Tricky, tricky. */
Packit aea12f
      t.c_lflag &= ~(ECHO | ISIG);
Packit aea12f
      tty_changed = (tcsetattr (fileno (in), TCSAFLUSH | TCSASOFT, &t) == 0);
Packit aea12f
    }
Packit aea12f
# endif
Packit aea12f
Packit aea12f
  /* Write the prompt.  */
Packit aea12f
  fputs_unlocked (prompt, out);
Packit aea12f
  fflush_unlocked (out);
Packit aea12f
Packit aea12f
  /* Read the password.  */
Packit aea12f
  nread = getline (&buf, &bufsize, in);
Packit aea12f
Packit aea12f
  /* According to the C standard, input may not be followed by output
Packit aea12f
     on the same stream without an intervening call to a file
Packit aea12f
     positioning function.  Suppose in == out; then without this fseek
Packit aea12f
     call, on Solaris, HP-UX, AIX, OSF/1, the previous input gets
Packit aea12f
     echoed, whereas on IRIX, the following newline is not output as
Packit aea12f
     it should be.  POSIX imposes similar restrictions if fileno (in)
Packit aea12f
     == fileno (out).  The POSIX restrictions are tricky and change
Packit aea12f
     from POSIX version to POSIX version, so play it safe and invoke
Packit aea12f
     fseek even if in != out.  */
Packit aea12f
  fseeko (out, 0, SEEK_CUR);
Packit aea12f
Packit aea12f
  if (buf != NULL)
Packit aea12f
    {
Packit aea12f
      if (nread < 0)
Packit aea12f
        buf[0] = '\0';
Packit aea12f
      else if (buf[nread - 1] == '\n')
Packit aea12f
        {
Packit aea12f
          /* Remove the newline.  */
Packit aea12f
          buf[nread - 1] = '\0';
Packit aea12f
          if (tty_changed)
Packit aea12f
            {
Packit aea12f
              /* Write the newline that was not echoed.  */
Packit aea12f
              putc_unlocked ('\n', out);
Packit aea12f
            }
Packit aea12f
        }
Packit aea12f
    }
Packit aea12f
Packit aea12f
  /* Restore the original setting.  */
Packit aea12f
# if HAVE_TCSETATTR
Packit aea12f
  if (tty_changed)
Packit aea12f
    tcsetattr (fileno (in), TCSAFLUSH | TCSASOFT, &s);
Packit aea12f
# endif
Packit aea12f
Packit aea12f
  funlockfile (out);
Packit aea12f
Packit aea12f
  call_fclose (tty);
Packit aea12f
Packit aea12f
  return buf;
Packit aea12f
}
Packit aea12f
Packit aea12f
#else /* W32 native */
Packit aea12f
Packit aea12f
/* Windows implementation by Martin Lambers <marlam@marlam.de>,
Packit aea12f
   improved by Simon Josefsson. */
Packit aea12f
Packit aea12f
/* For PASS_MAX. */
Packit aea12f
# include <limits.h>
Packit aea12f
/* For _getch(). */
Packit aea12f
# include <conio.h>
Packit aea12f
/* For strdup(). */
Packit aea12f
# include <string.h>
Packit aea12f
Packit aea12f
# ifndef PASS_MAX
Packit aea12f
#  define PASS_MAX 512
Packit aea12f
# endif
Packit aea12f
Packit aea12f
char *
Packit aea12f
getpass (const char *prompt)
Packit aea12f
{
Packit aea12f
  char getpassbuf[PASS_MAX + 1];
Packit aea12f
  size_t i = 0;
Packit aea12f
  int c;
Packit aea12f
Packit aea12f
  if (prompt)
Packit aea12f
    {
Packit aea12f
      fputs (prompt, stderr);
Packit aea12f
      fflush (stderr);
Packit aea12f
    }
Packit aea12f
Packit aea12f
  for (;;)
Packit aea12f
    {
Packit aea12f
      c = _getch ();
Packit aea12f
      if (c == '\r')
Packit aea12f
        {
Packit aea12f
          getpassbuf[i] = '\0';
Packit aea12f
          break;
Packit aea12f
        }
Packit aea12f
      else if (i < PASS_MAX)
Packit aea12f
        {
Packit aea12f
          getpassbuf[i++] = c;
Packit aea12f
        }
Packit aea12f
Packit aea12f
      if (i >= PASS_MAX)
Packit aea12f
        {
Packit aea12f
          getpassbuf[i] = '\0';
Packit aea12f
          break;
Packit aea12f
        }
Packit aea12f
    }
Packit aea12f
Packit aea12f
  if (prompt)
Packit aea12f
    {
Packit aea12f
      fputs ("\r\n", stderr);
Packit aea12f
      fflush (stderr);
Packit aea12f
    }
Packit aea12f
Packit aea12f
  return strdup (getpassbuf);
Packit aea12f
}
Packit aea12f
#endif