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