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