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