Blame src/gl/getpass.c

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