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