1 /*
2  * For license terms, see the file COPYING in this directory.
3  */
4 
5 /***********************************************************************
6   module:       getpass.c
7   project:      fetchmail
8   programmer:   Carl Harris, ceharris@mal.com
9   description: 	getpass() replacement which allows for long passwords.
10                 This version hacked by Wilfred Teiken, allowing the
11                 password to be piped to fetchmail.
12 
13  ***********************************************************************/
14 
15 #include "config.h"
16 
17 #include <stdio.h>
18 #include <signal.h>
19 #include <fcntl.h>
20 #if defined(HAVE_UNISTD_H)
21 #include <unistd.h>
22 #endif
23 #if defined(HAVE_STDLIB_H)
24 #include <stdlib.h>
25 #endif
26 #include "i18n.h"
27 #include "getpass.h"
28 
29 #define INPUT_BUF_SIZE	PASSWORDLEN
30 
31 #if defined(HAVE_TERMIOS_H) && defined(HAVE_TCSETATTR)
32 #  include <termios.h>
33 #else
34 #if defined(HAVE_TERMIO_H)
35 #  include <sys/ioctl.h>
36 #  include <termio.h>
37 #else
38 #if defined(HAVE_SGTTY_H)
39 #  include <sgtty.h>
40 #endif
41 #endif
42 #endif
43 
44 static int ttyfd;
45 
46 #if defined(HAVE_TCSETATTR)
47   static struct termios termb;
48   static tcflag_t flags;
49 #else
50 #if defined(HAVE_TERMIO_H)
51   static struct termio termb;
52   static unsigned short flags;
53 #else
54 #if defined(HAVE_STTY)
55   static struct sgttyb ttyb;
56   static int flags;
57 #endif
58 #endif
59 #endif
60 
61 void static save_tty_state(void);
62 void static disable_tty_echo(void);
63 void static restore_tty_state(void);
64 static RETSIGTYPE sigint_handler(int);
65 
fm_getpassword(const char * prompt)66 char *fm_getpassword(const char *prompt)
67 {
68 #if !(defined(HAVE_TCSETATTR) || defined(HAVE_TERMIO_H) || defined(HAVE_STTY))
69 #if defined(HAVE_GETPASS)
70     char *getpass();
71     return getpass(prompt);
72 #else
73     fputs(_("ERROR: no support for getpassword() routine\n"),stderr);
74     exit(1);
75 #endif
76 #else
77     register char *p;
78     register int c;
79     FILE *fi;
80     static char pbuf[INPUT_BUF_SIZE];
81     RETSIGTYPE (*sig)(int) = 0;	/* initialization pacifies -Wall */
82     RETSIGTYPE sigint_handler(int);
83     char *ret;
84 
85     int istty = isatty(0);
86 
87     /* get the file descriptor for the actual input device if it's a tty */
88     if (istty)
89     {
90 	if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
91 	    fi = stdin;
92 	else
93 	    setbuf(fi, (char *)NULL);
94     }
95     else
96 	fi = stdin;
97 
98     /* store descriptor for the tty */
99     ttyfd = fileno(fi);
100 
101     if (istty)
102     {
103 	/* preserve tty state before turning off echo */
104 	save_tty_state();
105 
106 	/* now that we have the current tty state, we can catch SIGINT and
107 	   exit gracefully */
108 	sig = signal(SIGINT, sigint_handler);
109 
110 	/* turn off echo on the tty */
111 	disable_tty_echo();
112 
113 	/* display the prompt and get the input string */
114 	fprintf(stderr, "%s", prompt);
115     }
116 
117     for (p = pbuf; (c = getc(fi))!='\n' && c!=EOF;)
118     {
119 	if (p < &pbuf[INPUT_BUF_SIZE - 1])
120 	    *p++ = c;
121     }
122     *p = '\0';
123 
124     if (c == EOF)
125 	ret = NULL;
126     else
127 	ret = pbuf;
128 
129     /* write a newline so cursor won't appear to hang */
130     if (fi != stdin)
131 	fprintf(stderr, "\n");
132 
133     if (istty)
134     {
135 	/* restore previous state of the tty */
136 	restore_tty_state();
137 
138 	/* restore previous state of SIGINT */
139 	signal(SIGINT, sig);
140     }
141     if (fi != stdin)
142 	fclose(fi);	/* not checking should be safe, file mode was "r" */
143 
144     return(ret);
145 #endif /* !(defined(HAVE_TCSETATTR) || ... */
146 }
147 
save_tty_state(void)148 static void save_tty_state (void)
149 {
150 #if defined(HAVE_TCSETATTR)
151     tcgetattr(ttyfd, &termb);
152     flags = termb.c_lflag;
153 #else
154 #if defined(HAVE_TERMIO_H)
155     ioctl(ttyfd, TCGETA, (char *) &termb);
156     flags = termb.c_lflag;
157 #else  /* we HAVE_STTY */
158     gtty(ttyfd, &ttyb);
159     flags = ttyb.sg_flags;
160 #endif
161 #endif
162 }
163 
disable_tty_echo(void)164 static void disable_tty_echo(void)
165 {
166     /* turn off echo on the tty */
167 #if defined(HAVE_TCSETATTR)
168     termb.c_lflag &= ~ECHO;
169     tcsetattr(ttyfd, TCSAFLUSH, &termb);
170 #else
171 #if defined(HAVE_TERMIO_H)
172     termb.c_lflag &= ~ECHO;
173     ioctl(ttyfd, TCSETA, (char *) &termb);
174 #else  /* we HAVE_STTY */
175     ttyb.sg_flags &= ~ECHO;
176     stty(ttyfd, &ttyb);
177 #endif
178 #endif
179 }
180 
restore_tty_state(void)181 static void restore_tty_state(void)
182 {
183     /* restore previous tty echo state */
184 #if defined(HAVE_TCSETATTR)
185     termb.c_lflag = flags;
186     tcsetattr(ttyfd, TCSAFLUSH, &termb);
187 #else
188 #if defined(HAVE_TERMIO_H)
189     termb.c_lflag = flags;
190     ioctl(ttyfd, TCSETA, (char *) &termb);
191 #else  /* we HAVE_STTY */
192     ttyb.sg_flags = flags;
193     stty(ttyfd, &ttyb);
194 #endif
195 #endif
196 }
197 
sigint_handler(int signum)198 static RETSIGTYPE sigint_handler(int signum)
199 {
200     restore_tty_state();
201     fprintf(stderr, _("\nCaught SIGINT... bailing out.\n"));
202     exit(1);
203 }
204 
205 /* getpass.c ends here */
206