26c8fdb0526872e3739ca4f2b7d976263b9e1545
[openafs.git] / src / des / read_pssword.c
1 /*
2  *
3  * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
4  * of Technology.
5  *
6  * For copying and distribution information, please see the file
7  * <mit-cpyright.h>.
8  *
9  * This routine prints the supplied string to standard
10  * output as a prompt, and reads a password string without
11  * echoing.
12  */
13
14 #include <afsconfig.h>
15 #include <afs/param.h>
16
17
18 #include <mit-cpyright.h>
19 #include <des.h>
20 #include "conf.h"
21
22 #include <stdio.h>
23 #ifdef HAVE_STRING_H
24 #include <string.h>
25 #else
26 #ifdef HAVE_STRINGS_H
27 #include <strings.h>
28 #endif
29 #endif
30
31 #ifdef  BSDUNIX
32 #ifdef  AFS_SUN5_ENV
33 #define BSD_COMP
34 #endif
35 #include <sys/ioctl.h>
36 #include <signal.h>
37 #include <setjmp.h>
38 #endif
39
40 #ifdef HAVE_SIGNAL_H
41 #include <signal.h>
42 #endif
43
44 #ifdef HAVE_UNISTD_H
45 #include <unistd.h>
46 #endif
47
48 #ifdef  AFS_HPUX_ENV
49 #include <bsdtty.h>
50 #include <sys/ttold.h>
51 #include <termios.h>
52 static int intrupt;
53 #endif
54
55 #ifdef HAVE_TERMIOS_H
56 #include <termios.h>
57 #endif
58
59 #ifdef HAVE_WINDOWS_H
60 #include <windows.h>
61 #endif
62
63 #ifdef HAVE_SYS_TYPES_H
64 #include <sys/types.h>
65 #endif
66
67 static int intrupt;
68 #if defined(AFS_SGI_ENV) || defined (AFS_AIX_ENV) || defined(AFS_XBSD_ENV)      /*|| defined (AFS_HPUX_ENV) || defined(AFS_SUN5_ENV) */
69 #undef  BSDUNIX
70 #endif
71
72 #ifdef  BSDUNIX
73 static jmp_buf env;
74 #endif
75
76 #ifdef BSDUNIX
77 #define POSIX
78 #ifdef POSIX
79 typedef void sigtype;
80 #else
81 typedef int sigtype;
82 #endif
83 static sigtype sig_restore();
84 static push_signals(), pop_signals();
85 #endif
86
87 #include "des_prototypes.h"
88
89 /*** Routines ****************************************************** */
90 int
91 des_read_password(des_cblock * k, char *prompt, int verify)
92 {
93     int ok;
94     char key_string[BUFSIZ];
95
96 #ifdef BSDUNIX
97     if (setjmp(env)) {
98         ok = -1;
99         goto lose;
100     }
101 #endif
102
103     ok = des_read_pw_string(key_string, BUFSIZ, prompt, verify);
104     if (ok == 0)
105         des_string_to_key(key_string, k);
106
107 #ifdef BSDUNIX
108   lose:
109 #endif
110     memset(key_string, 0, sizeof(key_string));
111     return ok;
112 }
113
114 #if     defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV) || defined(AFS_SGI_ENV) || defined(AFS_SUN_ENV) || defined(AFS_LINUX20_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
115 static void catch(int);
116 #endif
117
118 #if     !defined(BSDUNIX) && (defined(AFS_AIX_ENV) || defined (AFS_HPUX_ENV) || defined(AFS_SGI_ENV) || defined(AFS_LINUX20_ENV))
119 #include <termio.h>
120 #endif
121
122 /*
123  * This version just returns the string, doesn't map to key.
124  *
125  * Returns 0 on success, non-zero on failure.
126  */
127 int
128 des_read_pw_string(char *s, int maxa, char *prompt, int verify)
129 {
130     int ok = 0, cnt1 = 0;
131     char *ptr;
132 #if defined(AFS_HPUX_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
133     register int fno;
134     struct sigaction newsig, oldsig;
135     struct termios save_ttyb, ttyb;
136 #endif
137 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
138     FILE *fi;
139 #endif
140 #if     defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV)
141     struct termios ttyb;
142     struct sigaction osa, sa;
143 #endif
144 #ifdef BSDUNIX
145     jmp_buf old_env;
146     unsigned long flags;
147     struct sgttyb tty_state, echo_off_tty_state;
148     FILE *fi;
149 #else
150 #if     defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV) || defined(AFS_SGI_ENV) || defined(AFS_LINUX20_ENV)
151     struct termio ttyb;
152     FILE *fi;
153     char savel, flags;
154     void (*sig) ();
155 #endif
156 #endif
157 #ifdef AFS_NT40_ENV
158     HANDLE hConStdin;
159     DWORD oldConMode, newConMode;
160     BOOL resetConMode = FALSE;
161 #endif
162     char key_string[BUFSIZ];
163
164     if (maxa > BUFSIZ) {
165         return -1;
166     }
167 #if defined(AFS_HPUX_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
168     if ((fi = fopen("/dev/tty", "r")) == NULL)
169         return -1;
170     setbuf(fi, (char *)NULL);   /* We don't want any buffering for our i/o. */
171     /*
172      * Install signal handler for SIGINT so that we can restore
173      * the tty settings after we change them.  The handler merely
174      * increments the variable "intrupt" to tell us that an
175      * interrupt signal was received.
176      */
177     newsig.sa_handler = catch;
178     sigemptyset(&newsig.sa_mask);
179     newsig.sa_flags = 0;
180     sigaction(SIGINT, &newsig, &oldsig);
181     intrupt = 0;
182
183     /*
184      * Get the terminal characters (save for later restoration) and
185      * reset them so that echo is off
186      */
187     fno = fileno(fi);
188     tcgetattr(fno, &ttyb);
189     save_ttyb = ttyb;
190     ttyb.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
191     tcsetattr(fno, TCSAFLUSH, &ttyb);
192 #else
193 #if     defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV)
194     if ((fi = fopen("/dev/tty", "r")) == NULL) {
195         return (-1);
196     } else
197         setbuf(fi, (char *)NULL);
198     sa.sa_handler = catch;
199     sa.sa_mask = 0;
200     sa.sa_flags = SA_INTERRUPT;
201     (void)sigaction(SIGINT, &sa, &osa);
202     intrupt = 0;
203     (void)ioctl(fileno(fi), TCGETS, &ttyb);
204     flags = ttyb.c_lflag;
205     ttyb.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
206     (void)ioctl(fileno(fi), TCSETSF, &ttyb);
207 #else
208 #ifdef  BSDUNIX
209     /* XXX assume jmp_buf is typedef'ed to an array */
210     memcpy((char *)env, (char *)old_env, sizeof(env));
211     if (setjmp(env))
212         goto lose;
213     /* save terminal state */
214     if (ioctl(0, TIOCGETP, (char *)&tty_state) == -1)
215         return -1;
216     push_signals();
217     /* Turn off echo */
218     memcpy(&echo_off_tty_state, &tty_state, sizeof(tty_state));
219     echo_off_tty_state.sg_flags &= ~ECHO;
220     if (ioctl(0, TIOCSETP, (char *)&echo_off_tty_state) == -1)
221         return -1;
222 #else
223 #if     defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV) || defined(AFS_SGI_ENV) || defined(AFS_LINUX20_ENV)
224     if ((fi = fopen("/dev/tty", "r+")) == NULL)
225         return (-1);
226     else
227         setbuf(fi, (char *)NULL);
228     sig = signal(SIGINT, catch);
229     intrupt = 0;
230     (void)ioctl(fileno(fi), TCGETA, &ttyb);
231     savel = ttyb.c_line;
232     ttyb.c_line = 0;
233     flags = ttyb.c_lflag;
234     ttyb.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
235     (void)ioctl(fileno(fi), TCSETAF, &ttyb);
236 #else
237 #ifdef AFS_NT40_ENV
238     /* turn off console input echoing */
239     if ((hConStdin = GetStdHandle(STD_INPUT_HANDLE)) != INVALID_HANDLE_VALUE) {
240         if (GetConsoleMode(hConStdin, &oldConMode)) {
241             newConMode = (oldConMode & ~(ENABLE_ECHO_INPUT));
242             if (SetConsoleMode(hConStdin, newConMode)) {
243                 resetConMode = TRUE;
244             }
245         }
246     }
247 #endif
248 #endif
249 #endif
250 #endif
251 #endif
252     while (!ok) {
253         (void)printf(prompt);
254         (void)fflush(stdout);
255 #ifdef  CROSSMSDOS
256         h19line(s, sizeof(s), 0);
257         if (!strlen(s))
258             continue;
259 #else
260         if (!fgets(s, maxa, stdin)) {
261             clearerr(stdin);
262             printf("\n");
263             if (cnt1++ > 1) {
264                 /*
265                  * Otherwise hitting ctrl-d will always leave us inside this loop forever!
266                  */
267                 break;
268             }
269             continue;
270         }
271         if ((ptr = strchr(s, '\n')))
272             *ptr = '\0';
273 #endif
274         if (verify) {
275             printf("\nVerifying, please re-enter %s", prompt);
276             (void)fflush(stdout);
277 #ifdef CROSSMSDOS
278             h19line(key_string, sizeof(key_string), 0);
279             if (!strlen(key_string))
280                 continue;
281 #else
282             if (!fgets(key_string, sizeof(key_string), stdin)) {
283                 clearerr(stdin);
284                 continue;
285             }
286             if ((ptr = strchr(key_string, '\n')))
287                 *ptr = '\0';
288 #endif
289             if (strcmp(s, key_string)) {
290                 printf("\n\07\07Mismatch - try again\n");
291                 (void)fflush(stdout);
292                 continue;
293             }
294         }
295         ok = 1;
296     }
297
298 #ifdef BSDUNIX
299   lose:
300 #endif
301     if (!ok)
302         memset(s, 0, maxa);
303     printf("\n");
304 #if defined(AFS_HPUX_ENV) || defined(AFS_XBSD_ENV) || defined(AFS_DARWIN_ENV)
305     /*
306      * Restore the terminal to its previous characteristics.
307      * Restore the old signal handler for SIGINT.
308      */
309     tcsetattr(fno, TCSANOW, &save_ttyb);
310     sigaction(SIGINT, &oldsig, NULL);
311     if (fi != stdin)
312         fclose(fi);
313
314     /*
315      * If we got a SIGINT while we were doing things, send the SIGINT
316      * to ourselves so that the calling program receives it (since we
317      * were intercepting it for a period of time.)
318      */
319     if (intrupt)
320         kill(getpid(), SIGINT);
321 #else
322 #if     defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV)
323     ttyb.c_lflag = flags;
324     (void)ioctl(fileno(fi), TCSETSW, &ttyb);
325     (void)sigaction(SIGINT, &osa, (struct sigaction *)NULL);
326     if (fi != stdin)
327         (void)fclose(fi);
328 #else
329 #ifdef  BSDUNIX
330     if (ioctl(0, TIOCSETP, (char *)&tty_state))
331         ok = 0;
332     pop_signals();
333     memcpy((char *)old_env, (char *)env, sizeof(env));
334 #else
335 #if     defined (AFS_AIX_ENV) /*|| defined (AFS_HPUX_ENV)*/ || defined(AFS_SGI_ENV) || defined(AFS_LINUX20_ENV)
336     ttyb.c_lflag = flags;
337     ttyb.c_line = savel;
338     (void)ioctl(fileno(fi), TCSETAW, &ttyb);
339     (void)signal(SIGINT, sig);
340     if (fi != stdin)
341         (void)fclose(fi);
342     if (intrupt)
343         (void)kill(getpid(), SIGINT);
344 #else
345 #ifdef AFS_NT40_ENV
346     /* restore console to original mode settings */
347     if (resetConMode) {
348         (void)SetConsoleMode(hConStdin, oldConMode);
349     }
350 #endif
351 #endif
352 #endif
353 #endif
354 #endif
355     if (verify)
356         memset(key_string, 0, sizeof(key_string));
357     s[maxa - 1] = 0;            /* force termination */
358     return !ok;                 /* return nonzero if not okay */
359 }
360
361 #ifdef  BSDUNIX
362 /*
363  * this can be static since we should never have more than
364  * one set saved....
365  */
366 #ifdef mips
367 void static (*old_sigfunc[NSIG]) ();
368 #else
369 static sigtype(*old_sigfunc[NSIG]) ();
370 #endif
371
372 static
373 push_signals()
374 {
375     register i;
376     for (i = 0; i < NSIG; i++)
377         old_sigfunc[i] = signal(i, sig_restore);
378 }
379
380 static
381 pop_signals()
382 {
383     register i;
384     for (i = 0; i < NSIG; i++)
385         (void)signal(i, old_sigfunc[i]);
386 }
387
388 static sigtype
389 sig_restore()
390 {
391     longjmp(env, 1);
392 }
393 #endif
394
395
396 #if     defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV) || defined(AFS_SGI_ENV) || defined(AFS_SUN_ENV) || defined(AFS_LINUX20_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
397 static void
398 catch(int junk)
399 {
400     ++intrupt;
401 }
402 #endif