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
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
    register char *p;
76
    register 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
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
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
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
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 */