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