xref: /dflybsd-src/contrib/cvs-1.12/lib/getpass.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
1*86d7f5d3SJohn Marino /* Copyright (C) 1992-2001, 2003, 2004, 2005 Free Software Foundation, Inc.
2*86d7f5d3SJohn Marino    This file is part of the GNU C Library.
3*86d7f5d3SJohn Marino 
4*86d7f5d3SJohn Marino    This program is free software; you can redistribute it and/or modify
5*86d7f5d3SJohn Marino    it under the terms of the GNU General Public License as published by
6*86d7f5d3SJohn Marino    the Free Software Foundation; either version 2, or (at your option)
7*86d7f5d3SJohn Marino    any later version.
8*86d7f5d3SJohn Marino 
9*86d7f5d3SJohn Marino    This program is distributed in the hope that it will be useful,
10*86d7f5d3SJohn Marino    but WITHOUT ANY WARRANTY; without even the implied warranty of
11*86d7f5d3SJohn Marino    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*86d7f5d3SJohn Marino    GNU General Public License for more details.
13*86d7f5d3SJohn Marino 
14*86d7f5d3SJohn Marino    You should have received a copy of the GNU General Public License along
15*86d7f5d3SJohn Marino    with this program; if not, write to the Free Software Foundation,
16*86d7f5d3SJohn Marino    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
17*86d7f5d3SJohn Marino 
18*86d7f5d3SJohn Marino #ifdef HAVE_CONFIG_H
19*86d7f5d3SJohn Marino # include <config.h>
20*86d7f5d3SJohn Marino #endif
21*86d7f5d3SJohn Marino 
22*86d7f5d3SJohn Marino #include "getpass.h"
23*86d7f5d3SJohn Marino 
24*86d7f5d3SJohn Marino #include <stdio.h>
25*86d7f5d3SJohn Marino 
26*86d7f5d3SJohn Marino #if !defined _WIN32
27*86d7f5d3SJohn Marino 
28*86d7f5d3SJohn Marino #include <stdbool.h>
29*86d7f5d3SJohn Marino 
30*86d7f5d3SJohn Marino #if HAVE_STDIO_EXT_H
31*86d7f5d3SJohn Marino # include <stdio_ext.h>
32*86d7f5d3SJohn Marino #endif
33*86d7f5d3SJohn Marino #if !HAVE___FSETLOCKING
34*86d7f5d3SJohn Marino # define __fsetlocking(stream, type)	/* empty */
35*86d7f5d3SJohn Marino #endif
36*86d7f5d3SJohn Marino 
37*86d7f5d3SJohn Marino #if HAVE_TERMIOS_H
38*86d7f5d3SJohn Marino # include <termios.h>
39*86d7f5d3SJohn Marino #endif
40*86d7f5d3SJohn Marino 
41*86d7f5d3SJohn Marino #include "getline.h"
42*86d7f5d3SJohn Marino 
43*86d7f5d3SJohn Marino #if USE_UNLOCKED_IO
44*86d7f5d3SJohn Marino # include "unlocked-io.h"
45*86d7f5d3SJohn Marino #else
46*86d7f5d3SJohn Marino # if !HAVE_DECL_FFLUSH_UNLOCKED
47*86d7f5d3SJohn Marino #  undef fflush_unlocked
48*86d7f5d3SJohn Marino #  define fflush_unlocked(x) fflush (x)
49*86d7f5d3SJohn Marino # endif
50*86d7f5d3SJohn Marino # if !HAVE_DECL_FLOCKFILE
51*86d7f5d3SJohn Marino #  undef flockfile
52*86d7f5d3SJohn Marino #  define flockfile(x) ((void) 0)
53*86d7f5d3SJohn Marino # endif
54*86d7f5d3SJohn Marino # if !HAVE_DECL_FUNLOCKFILE
55*86d7f5d3SJohn Marino #  undef funlockfile
56*86d7f5d3SJohn Marino #  define funlockfile(x) ((void) 0)
57*86d7f5d3SJohn Marino # endif
58*86d7f5d3SJohn Marino # if !HAVE_DECL_FPUTS_UNLOCKED
59*86d7f5d3SJohn Marino #  undef fputs_unlocked
60*86d7f5d3SJohn Marino #  define fputs_unlocked(str,stream) fputs (str, stream)
61*86d7f5d3SJohn Marino # endif
62*86d7f5d3SJohn Marino # if !HAVE_DECL_PUTC_UNLOCKED
63*86d7f5d3SJohn Marino #  undef putc_unlocked
64*86d7f5d3SJohn Marino #  define putc_unlocked(c,stream) putc (c, stream)
65*86d7f5d3SJohn Marino # endif
66*86d7f5d3SJohn Marino #endif
67*86d7f5d3SJohn Marino 
68*86d7f5d3SJohn Marino /* It is desirable to use this bit on systems that have it.
69*86d7f5d3SJohn Marino    The only bit of terminal state we want to twiddle is echoing, which is
70*86d7f5d3SJohn Marino    done in software; there is no need to change the state of the terminal
71*86d7f5d3SJohn Marino    hardware.  */
72*86d7f5d3SJohn Marino 
73*86d7f5d3SJohn Marino #ifndef TCSASOFT
74*86d7f5d3SJohn Marino # define TCSASOFT 0
75*86d7f5d3SJohn Marino #endif
76*86d7f5d3SJohn Marino 
77*86d7f5d3SJohn Marino static void
call_fclose(void * arg)78*86d7f5d3SJohn Marino call_fclose (void *arg)
79*86d7f5d3SJohn Marino {
80*86d7f5d3SJohn Marino   if (arg != NULL)
81*86d7f5d3SJohn Marino     fclose (arg);
82*86d7f5d3SJohn Marino }
83*86d7f5d3SJohn Marino 
84*86d7f5d3SJohn Marino char *
getpass(const char * prompt)85*86d7f5d3SJohn Marino getpass (const char *prompt)
86*86d7f5d3SJohn Marino {
87*86d7f5d3SJohn Marino   FILE *tty;
88*86d7f5d3SJohn Marino   FILE *in, *out;
89*86d7f5d3SJohn Marino   struct termios s, t;
90*86d7f5d3SJohn Marino   bool tty_changed = false;
91*86d7f5d3SJohn Marino   static char *buf;
92*86d7f5d3SJohn Marino   static size_t bufsize;
93*86d7f5d3SJohn Marino   ssize_t nread;
94*86d7f5d3SJohn Marino 
95*86d7f5d3SJohn Marino   /* Try to write to and read from the terminal if we can.
96*86d7f5d3SJohn Marino      If we can't open the terminal, use stderr and stdin.  */
97*86d7f5d3SJohn Marino 
98*86d7f5d3SJohn Marino   tty = fopen ("/dev/tty", "w+");
99*86d7f5d3SJohn Marino   if (tty == NULL)
100*86d7f5d3SJohn Marino     {
101*86d7f5d3SJohn Marino       in = stdin;
102*86d7f5d3SJohn Marino       out = stderr;
103*86d7f5d3SJohn Marino     }
104*86d7f5d3SJohn Marino   else
105*86d7f5d3SJohn Marino     {
106*86d7f5d3SJohn Marino       /* We do the locking ourselves.  */
107*86d7f5d3SJohn Marino       __fsetlocking (tty, FSETLOCKING_BYCALLER);
108*86d7f5d3SJohn Marino 
109*86d7f5d3SJohn Marino       out = in = tty;
110*86d7f5d3SJohn Marino     }
111*86d7f5d3SJohn Marino 
112*86d7f5d3SJohn Marino   flockfile (out);
113*86d7f5d3SJohn Marino 
114*86d7f5d3SJohn Marino   /* Turn echoing off if it is on now.  */
115*86d7f5d3SJohn Marino #if HAVE_TCGETATTR
116*86d7f5d3SJohn Marino   if (tcgetattr (fileno (in), &t) == 0)
117*86d7f5d3SJohn Marino     {
118*86d7f5d3SJohn Marino       /* Save the old one. */
119*86d7f5d3SJohn Marino       s = t;
120*86d7f5d3SJohn Marino       /* Tricky, tricky. */
121*86d7f5d3SJohn Marino       t.c_lflag &= ~(ECHO | ISIG);
122*86d7f5d3SJohn Marino       tty_changed = (tcsetattr (fileno (in), TCSAFLUSH | TCSASOFT, &t) == 0);
123*86d7f5d3SJohn Marino     }
124*86d7f5d3SJohn Marino #endif
125*86d7f5d3SJohn Marino 
126*86d7f5d3SJohn Marino   /* Write the prompt.  */
127*86d7f5d3SJohn Marino   fputs_unlocked (prompt, out);
128*86d7f5d3SJohn Marino   fflush_unlocked (out);
129*86d7f5d3SJohn Marino 
130*86d7f5d3SJohn Marino   /* Read the password.  */
131*86d7f5d3SJohn Marino   nread = getline (&buf, &bufsize, in);
132*86d7f5d3SJohn Marino 
133*86d7f5d3SJohn Marino   /* According to the C standard, input may not be followed by output
134*86d7f5d3SJohn Marino      on the same stream without an intervening call to a file
135*86d7f5d3SJohn Marino      positioning function.  Suppose in == out; then without this fseek
136*86d7f5d3SJohn Marino      call, on Solaris, HP-UX, AIX, OSF/1, the previous input gets
137*86d7f5d3SJohn Marino      echoed, whereas on IRIX, the following newline is not output as
138*86d7f5d3SJohn Marino      it should be.  POSIX imposes similar restrictions if fileno (in)
139*86d7f5d3SJohn Marino      == fileno (out).  The POSIX restrictions are tricky and change
140*86d7f5d3SJohn Marino      from POSIX version to POSIX version, so play it safe and invoke
141*86d7f5d3SJohn Marino      fseek even if in != out.  */
142*86d7f5d3SJohn Marino   fseek (out, 0, SEEK_CUR);
143*86d7f5d3SJohn Marino 
144*86d7f5d3SJohn Marino   if (buf != NULL)
145*86d7f5d3SJohn Marino     {
146*86d7f5d3SJohn Marino       if (nread < 0)
147*86d7f5d3SJohn Marino 	buf[0] = '\0';
148*86d7f5d3SJohn Marino       else if (buf[nread - 1] == '\n')
149*86d7f5d3SJohn Marino 	{
150*86d7f5d3SJohn Marino 	  /* Remove the newline.  */
151*86d7f5d3SJohn Marino 	  buf[nread - 1] = '\0';
152*86d7f5d3SJohn Marino 	  if (tty_changed)
153*86d7f5d3SJohn Marino 	    {
154*86d7f5d3SJohn Marino 	      /* Write the newline that was not echoed.  */
155*86d7f5d3SJohn Marino 	      putc_unlocked ('\n', out);
156*86d7f5d3SJohn Marino 	    }
157*86d7f5d3SJohn Marino 	}
158*86d7f5d3SJohn Marino     }
159*86d7f5d3SJohn Marino 
160*86d7f5d3SJohn Marino   /* Restore the original setting.  */
161*86d7f5d3SJohn Marino #if HAVE_TCSETATTR
162*86d7f5d3SJohn Marino   if (tty_changed)
163*86d7f5d3SJohn Marino     tcsetattr (fileno (in), TCSAFLUSH | TCSASOFT, &s);
164*86d7f5d3SJohn Marino #endif
165*86d7f5d3SJohn Marino 
166*86d7f5d3SJohn Marino   funlockfile (out);
167*86d7f5d3SJohn Marino 
168*86d7f5d3SJohn Marino   call_fclose (tty);
169*86d7f5d3SJohn Marino 
170*86d7f5d3SJohn Marino   return buf;
171*86d7f5d3SJohn Marino }
172*86d7f5d3SJohn Marino 
173*86d7f5d3SJohn Marino #else /* WIN32 */
174*86d7f5d3SJohn Marino 
175*86d7f5d3SJohn Marino /* Windows implementation by Martin Lambers <marlam@marlam.de>,
176*86d7f5d3SJohn Marino    improved by Simon Josefsson. */
177*86d7f5d3SJohn Marino 
178*86d7f5d3SJohn Marino /* For PASS_MAX. */
179*86d7f5d3SJohn Marino #include <limits.h>
180*86d7f5d3SJohn Marino 
181*86d7f5d3SJohn Marino #ifndef PASS_MAX
182*86d7f5d3SJohn Marino # define PASS_MAX 512
183*86d7f5d3SJohn Marino #endif
184*86d7f5d3SJohn Marino 
185*86d7f5d3SJohn Marino char *
getpass(const char * prompt)186*86d7f5d3SJohn Marino getpass (const char *prompt)
187*86d7f5d3SJohn Marino {
188*86d7f5d3SJohn Marino   char getpassbuf[PASS_MAX + 1];
189*86d7f5d3SJohn Marino   size_t i = 0;
190*86d7f5d3SJohn Marino   int c;
191*86d7f5d3SJohn Marino 
192*86d7f5d3SJohn Marino   if (prompt)
193*86d7f5d3SJohn Marino     {
194*86d7f5d3SJohn Marino       fputs (prompt, stderr);
195*86d7f5d3SJohn Marino       fflush (stderr);
196*86d7f5d3SJohn Marino     }
197*86d7f5d3SJohn Marino 
198*86d7f5d3SJohn Marino   for (;;)
199*86d7f5d3SJohn Marino     {
200*86d7f5d3SJohn Marino       c = _getch ();
201*86d7f5d3SJohn Marino       if (c == '\r')
202*86d7f5d3SJohn Marino 	{
203*86d7f5d3SJohn Marino 	  getpassbuf[i] = '\0';
204*86d7f5d3SJohn Marino 	  break;
205*86d7f5d3SJohn Marino 	}
206*86d7f5d3SJohn Marino       else if (i < PASS_MAX)
207*86d7f5d3SJohn Marino 	{
208*86d7f5d3SJohn Marino 	  getpassbuf[i++] = c;
209*86d7f5d3SJohn Marino 	}
210*86d7f5d3SJohn Marino 
211*86d7f5d3SJohn Marino       if (i >= PASS_MAX)
212*86d7f5d3SJohn Marino 	{
213*86d7f5d3SJohn Marino 	  getpassbuf[i] = '\0';
214*86d7f5d3SJohn Marino 	  break;
215*86d7f5d3SJohn Marino 	}
216*86d7f5d3SJohn Marino     }
217*86d7f5d3SJohn Marino 
218*86d7f5d3SJohn Marino   if (prompt)
219*86d7f5d3SJohn Marino     {
220*86d7f5d3SJohn Marino       fputs ("\r\n", stderr);
221*86d7f5d3SJohn Marino       fflush (stderr);
222*86d7f5d3SJohn Marino     }
223*86d7f5d3SJohn Marino 
224*86d7f5d3SJohn Marino   return strdup (getpassbuf);
225*86d7f5d3SJohn Marino }
226*86d7f5d3SJohn Marino #endif
227