view lib/getpass.c @ 13761:a19ace3ba849

Avoid line length limitation from HP NonStop system header files. * m4/include_next.m4 (gl_INCLUDE_NEXT): Define also PRAGMA_COLUMNS. * lib/arpa_inet.in.h: Use PRAGMA_COLUMNS. * lib/ctype.in.h: Likewise. * lib/dirent.in.h: Likewise. * lib/errno.in.h: Likewise. * lib/fcntl.in.h: Likewise. * lib/float.in.h: Likewise. * lib/getopt.in.h: Likewise. * lib/iconv.in.h: Likewise. * lib/inttypes.in.h: Likewise. * lib/langinfo.in.h: Likewise. * lib/locale.in.h: Likewise. * lib/math.in.h: Likewise. * lib/netdb.in.h: Likewise. * lib/netinet_in.in.h: Likewise. * lib/poll.in.h: Likewise. * lib/pthread.in.h: Likewise. * lib/pty.in.h: Likewise. * lib/sched.in.h: Likewise. * lib/se-selinux.in.h: Likewise. * lib/search.in.h: Likewise. * lib/signal.in.h: Likewise. * lib/spawn.in.h: Likewise. * lib/stdarg.in.h: Likewise. * lib/stddef.in.h: Likewise. * lib/stdint.in.h: Likewise. * lib/stdio.in.h: Likewise. * lib/stdlib.in.h: Likewise. * lib/string.in.h: Likewise. * lib/strings.in.h: Likewise. * lib/sys_file.in.h: Likewise. * lib/sys_ioctl.in.h: Likewise. * lib/sys_select.in.h: Likewise. * lib/sys_socket.in.h: Likewise. * lib/sys_stat.in.h: Likewise. * lib/sys_time.in.h: Likewise. * lib/sys_times.in.h: Likewise. * lib/sys_utsname.in.h: Likewise. * lib/sys_wait.in.h: Likewise. * lib/sysexits.in.h: Likewise. * lib/termios.in.h: Likewise. * lib/time.in.h: Likewise. * lib/unistd.in.h: Likewise. * lib/wchar.in.h: Likewise. * lib/wctype.in.h: Likewise. * modules/arpa_inet (Makefile.am): Substitute PRAGMA_COLUMNS. * modules/ctype (Makefile.am): Likewise. * modules/dirent (Makefile.am): Likewise. * modules/errno (Makefile.am): Likewise. * modules/fcntl-h (Makefile.am): Likewise. * modules/float (Makefile.am): Likewise. * modules/getopt-posix (Makefile.am): Likewise. * modules/iconv-h (Makefile.am): Likewise. * modules/inttypes (Makefile.am): Likewise. * modules/langinfo (Makefile.am): Likewise. * modules/locale (Makefile.am): Likewise. * modules/math (Makefile.am): Likewise. * modules/netdb (Makefile.am): Likewise. * modules/netinet_in (Makefile.am): Likewise. * modules/poll-h (Makefile.am): Likewise. * modules/pthread (Makefile.am): Likewise. * modules/pty (Makefile.am): Likewise. * modules/sched (Makefile.am): Likewise. * modules/search (Makefile.am): Likewise. * modules/selinux-h (Makefile.am): Likewise. * modules/signal (Makefile.am): Likewise. * modules/spawn (Makefile.am): Likewise. * modules/stdarg (Makefile.am): Likewise. * modules/stddef (Makefile.am): Likewise. * modules/stdint (Makefile.am): Likewise. * modules/stdio (Makefile.am): Likewise. * modules/stdlib (Makefile.am): Likewise. * modules/string (Makefile.am): Likewise. * modules/strings (Makefile.am): Likewise. * modules/sys_file (Makefile.am): Likewise. * modules/sys_ioctl (Makefile.am): Likewise. * modules/sys_select (Makefile.am): Likewise. * modules/sys_socket (Makefile.am): Likewise. * modules/sys_stat (Makefile.am): Likewise. * modules/sys_time (Makefile.am): Likewise. * modules/sys_times (Makefile.am): Likewise. * modules/sys_utsname (Makefile.am): Likewise. * modules/sys_wait (Makefile.am): Likewise. * modules/sysexits (Makefile.am): Likewise. * modules/termios (Makefile.am): Likewise. * modules/time (Makefile.am): Likewise. * modules/unistd (Makefile.am): Likewise. * modules/wchar (Makefile.am): Likewise. * modules/wctype (Makefile.am): Likewise.
author Bruno Haible <bruno@clisp.org>
date Mon, 04 Oct 2010 23:35:51 +0200
parents c2cbabec01dd
children 97fc9a21a8fb
line wrap: on
line source

/* Copyright (C) 1992-2001, 2003-2007, 2009-2010 Free Software Foundation, Inc.

   This file is part of the GNU C Library.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License along
   with this program; if not, write to the Free Software Foundation,
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */

#ifndef _LIBC
# include <config.h>
#endif

#include "getpass.h"

#include <stdio.h>

#if !((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__)

#include <stdbool.h>

#if HAVE_DECL___FSETLOCKING && HAVE___FSETLOCKING
# if HAVE_STDIO_EXT_H
#  include <stdio_ext.h>
# endif
#else
# define __fsetlocking(stream, type)    /* empty */
#endif

#if HAVE_TERMIOS_H
# include <termios.h>
#endif

#if USE_UNLOCKED_IO
# include "unlocked-io.h"
#else
# if !HAVE_DECL_FFLUSH_UNLOCKED
#  undef fflush_unlocked
#  define fflush_unlocked(x) fflush (x)
# endif
# if !HAVE_DECL_FLOCKFILE
#  undef flockfile
#  define flockfile(x) ((void) 0)
# endif
# if !HAVE_DECL_FUNLOCKFILE
#  undef funlockfile
#  define funlockfile(x) ((void) 0)
# endif
# if !HAVE_DECL_FPUTS_UNLOCKED
#  undef fputs_unlocked
#  define fputs_unlocked(str,stream) fputs (str, stream)
# endif
# if !HAVE_DECL_PUTC_UNLOCKED
#  undef putc_unlocked
#  define putc_unlocked(c,stream) putc (c, stream)
# endif
#endif

/* It is desirable to use this bit on systems that have it.
   The only bit of terminal state we want to twiddle is echoing, which is
   done in software; there is no need to change the state of the terminal
   hardware.  */

#ifndef TCSASOFT
# define TCSASOFT 0
#endif

static void
call_fclose (void *arg)
{
  if (arg != NULL)
    fclose (arg);
}

char *
getpass (const char *prompt)
{
  FILE *tty;
  FILE *in, *out;
  struct termios s, t;
  bool tty_changed = false;
  static char *buf;
  static size_t bufsize;
  ssize_t nread;

  /* Try to write to and read from the terminal if we can.
     If we can't open the terminal, use stderr and stdin.  */

  tty = fopen ("/dev/tty", "w+");
  if (tty == NULL)
    {
      in = stdin;
      out = stderr;
    }
  else
    {
      /* We do the locking ourselves.  */
      __fsetlocking (tty, FSETLOCKING_BYCALLER);

      out = in = tty;
    }

  flockfile (out);

  /* Turn echoing off if it is on now.  */
#if HAVE_TCGETATTR
  if (tcgetattr (fileno (in), &t) == 0)
    {
      /* Save the old one. */
      s = t;
      /* Tricky, tricky. */
      t.c_lflag &= ~(ECHO | ISIG);
      tty_changed = (tcsetattr (fileno (in), TCSAFLUSH | TCSASOFT, &t) == 0);
    }
#endif

  /* Write the prompt.  */
  fputs_unlocked (prompt, out);
  fflush_unlocked (out);

  /* Read the password.  */
  nread = getline (&buf, &bufsize, in);

  /* According to the C standard, input may not be followed by output
     on the same stream without an intervening call to a file
     positioning function.  Suppose in == out; then without this fseek
     call, on Solaris, HP-UX, AIX, OSF/1, the previous input gets
     echoed, whereas on IRIX, the following newline is not output as
     it should be.  POSIX imposes similar restrictions if fileno (in)
     == fileno (out).  The POSIX restrictions are tricky and change
     from POSIX version to POSIX version, so play it safe and invoke
     fseek even if in != out.  */
  fseeko (out, 0, SEEK_CUR);

  if (buf != NULL)
    {
      if (nread < 0)
        buf[0] = '\0';
      else if (buf[nread - 1] == '\n')
        {
          /* Remove the newline.  */
          buf[nread - 1] = '\0';
          if (tty_changed)
            {
              /* Write the newline that was not echoed.  */
              putc_unlocked ('\n', out);
            }
        }
    }

  /* Restore the original setting.  */
#if HAVE_TCSETATTR
  if (tty_changed)
    tcsetattr (fileno (in), TCSAFLUSH | TCSASOFT, &s);
#endif

  funlockfile (out);

  call_fclose (tty);

  return buf;
}

#else /* W32 native */

/* Windows implementation by Martin Lambers <marlam@marlam.de>,
   improved by Simon Josefsson. */

/* For PASS_MAX. */
#include <limits.h>
/* For _getch(). */
#include <conio.h>
/* For strdup(). */
#include <string.h>

#ifndef PASS_MAX
# define PASS_MAX 512
#endif

char *
getpass (const char *prompt)
{
  char getpassbuf[PASS_MAX + 1];
  size_t i = 0;
  int c;

  if (prompt)
    {
      fputs (prompt, stderr);
      fflush (stderr);
    }

  for (;;)
    {
      c = _getch ();
      if (c == '\r')
        {
          getpassbuf[i] = '\0';
          break;
        }
      else if (i < PASS_MAX)
        {
          getpassbuf[i++] = c;
        }

      if (i >= PASS_MAX)
        {
          getpassbuf[i] = '\0';
          break;
        }
    }

  if (prompt)
    {
      fputs ("\r\n", stderr);
      fflush (stderr);
    }

  return strdup (getpassbuf);
}
#endif