Workaround for a Win95 console bug triggered by the password read stuff.
[openssl.git] / crypto / des / read_pwd.c
1 /* crypto/des/read_pwd.c */
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3  * All rights reserved.
4  *
5  * This package is an SSL implementation written
6  * by Eric Young (eay@cryptsoft.com).
7  * The implementation was written so as to conform with Netscapes SSL.
8  * 
9  * This library is free for commercial and non-commercial use as long as
10  * the following conditions are aheared to.  The following conditions
11  * apply to all code found in this distribution, be it the RC4, RSA,
12  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13  * included with this distribution is covered by the same copyright terms
14  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15  * 
16  * Copyright remains Eric Young's, and as such any Copyright notices in
17  * the code are not to be removed.
18  * If this package is used in a product, Eric Young should be given attribution
19  * as the author of the parts of the library used.
20  * This can be in the form of a textual message at program startup or
21  * in documentation (online or textual) provided with the package.
22  * 
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  * 3. All advertising materials mentioning features or use of this software
32  *    must display the following acknowledgement:
33  *    "This product includes cryptographic software written by
34  *     Eric Young (eay@cryptsoft.com)"
35  *    The word 'cryptographic' can be left out if the rouines from the library
36  *    being used are not cryptographic related :-).
37  * 4. If you include any Windows specific code (or a derivative thereof) from 
38  *    the apps directory (application code) you must include an acknowledgement:
39  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40  * 
41  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  * 
53  * The licence and distribution terms for any publically available version or
54  * derivative of this code cannot be changed.  i.e. this code cannot simply be
55  * copied and put under another distribution licence
56  * [including the GNU Public Licence.]
57  */
58
59 /* #define SIGACTION */ /* Define this if you have sigaction() */
60 #ifdef WIN16TTY
61 #undef WIN16
62 #undef _WINDOWS
63 #include <graph.h>
64 #endif
65
66 #if defined(WIN32) && !defined(WINNT)
67 #define WIN_CONSOLE_BUG
68 #endif
69
70
71 /* 06-Apr-92 Luke Brennan    Support for VMS */
72 #include "des_locl.h"
73 #include <signal.h>
74 #include <string.h>
75 #include <setjmp.h>
76 #include <errno.h>
77
78 #ifdef WIN_CONSOLE_BUG
79 #include <windows.h>
80 #include <wincon.h>
81 #endif
82
83
84 /* There are 5 types of terminal interface supported,
85  * TERMIO, TERMIOS, VMS, MSDOS and SGTTY
86  */
87
88 #if defined(__sgi) && !defined(TERMIOS)
89 #define TERMIOS
90 #undef  TERMIO
91 #undef  SGTTY
92 #endif
93
94 #if defined(linux) && !defined(TERMIO)
95 #undef  TERMIOS
96 #define TERMIO
97 #undef  SGTTY
98 #endif
99
100 #ifdef _LIBC
101 #undef  TERMIOS
102 #define TERMIO
103 #undef  SGTTY
104 #endif
105
106 #if !defined(TERMIO) && !defined(TERMIOS) && !defined(VMS) && !defined(MSDOS)
107 #undef  TERMIOS
108 #undef  TERMIO
109 #define SGTTY
110 #endif
111
112 #ifdef TERMIOS
113 #include <termios.h>
114 #define TTY_STRUCT              struct termios
115 #define TTY_FLAGS               c_lflag
116 #define TTY_get(tty,data)       tcgetattr(tty,data)
117 #define TTY_set(tty,data)       tcsetattr(tty,TCSANOW,data)
118 #endif
119
120 #ifdef TERMIO
121 #include <termio.h>
122 #define TTY_STRUCT              struct termio
123 #define TTY_FLAGS               c_lflag
124 #define TTY_get(tty,data)       ioctl(tty,TCGETA,data)
125 #define TTY_set(tty,data)       ioctl(tty,TCSETA,data)
126 #endif
127
128 #ifdef SGTTY
129 #include <sgtty.h>
130 #define TTY_STRUCT              struct sgttyb
131 #define TTY_FLAGS               sg_flags
132 #define TTY_get(tty,data)       ioctl(tty,TIOCGETP,data)
133 #define TTY_set(tty,data)       ioctl(tty,TIOCSETP,data)
134 #endif
135
136 #if !defined(_LIBC) && !defined(MSDOS) && !defined(VMS)
137 #include <sys/ioctl.h>
138 #endif
139
140 #ifdef MSDOS
141 #include <conio.h>
142 #define fgets(a,b,c) noecho_fgets(a,b,c)
143 #endif
144
145 #ifdef VMS
146 #include <ssdef.h>
147 #include <iodef.h>
148 #include <ttdef.h>
149 #include <descrip.h>
150 struct IOSB {
151         short iosb$w_value;
152         short iosb$w_count;
153         long  iosb$l_info;
154         };
155 #endif
156
157 #ifndef NX509_SIG
158 #define NX509_SIG 32
159 #endif
160
161 #ifndef NOPROTO
162 static void read_till_nl(FILE *);
163 static void recsig(int);
164 static void pushsig(void);
165 static void popsig(void);
166 #if defined(MSDOS) && !defined(WIN16)
167 static int noecho_fgets(char *buf, int size, FILE *tty);
168 #endif
169 #else
170 static void read_till_nl();
171 static void recsig();
172 static void pushsig();
173 static void popsig();
174 #if defined(MSDOS) && !defined(WIN16)
175 static int noecho_fgets();
176 #endif
177 #endif
178
179 #ifdef SIGACTION
180  static struct sigaction savsig[NX509_SIG];
181 #else
182 # ifndef NOPROTO
183   static void (*savsig[NX509_SIG])(int );
184 # else
185   static void (*savsig[NX509_SIG])();
186 # endif
187 #endif
188 static jmp_buf save;
189
190 int des_read_pw_string(buf, length, prompt, verify)
191 char *buf;
192 int length;
193 const char *prompt;
194 int verify;
195         {
196         char buff[BUFSIZ];
197         int ret;
198
199         ret=des_read_pw(buf,buff,(length>BUFSIZ)?BUFSIZ:length,prompt,verify);
200         memset(buff,0,BUFSIZ);
201         return(ret);
202         }
203
204 #ifndef WIN16
205
206 static void read_till_nl(in)
207 FILE *in;
208         {
209 #define SIZE 4
210         char buf[SIZE+1];
211
212         do      {
213                 fgets(buf,SIZE,in);
214                 } while (strchr(buf,'\n') == NULL);
215         }
216
217
218 /* return 0 if ok, 1 (or -1) otherwise */
219 int des_read_pw(buf, buff, size, prompt, verify)
220 char *buf;
221 char *buff;
222 int size;
223 const char *prompt;
224 int verify;
225         {
226 #ifdef VMS
227         struct IOSB iosb;
228         $DESCRIPTOR(terminal,"TT");
229         long tty_orig[3], tty_new[3];
230         long status;
231         unsigned short channel = 0;
232 #else
233 #ifndef MSDOS
234         TTY_STRUCT tty_orig,tty_new;
235 #endif
236 #endif
237         int number;
238         int ok;
239         /* statics are simply to avoid warnings about longjmp clobbering
240            things */
241         static int ps;
242         int is_a_tty;
243         static FILE *tty;
244         char *p;
245
246         if (setjmp(save))
247                 {
248                 ok=0;
249                 goto error;
250                 }
251
252         number=5;
253         ok=0;
254         ps=0;
255         is_a_tty=1;
256         tty=NULL;
257
258 #ifndef MSDOS
259         if ((tty=fopen("/dev/tty","r")) == NULL)
260                 tty=stdin;
261 #else /* MSDOS */
262         if ((tty=fopen("con","r")) == NULL)
263                 tty=stdin;
264 #endif /* MSDOS */
265
266 #if defined(TTY_get) && !defined(VMS)
267         if (TTY_get(fileno(tty),&tty_orig) == -1)
268                 {
269 #ifdef ENOTTY
270                 if (errno == ENOTTY)
271                         is_a_tty=0;
272                 else
273 #endif
274 #ifdef EINVAL
275                 /* Ariel Glenn ariel@columbia.edu reports that solaris
276                  * can return EINVAL instead.  This should be ok */
277                 if (errno == EINVAL)
278                         is_a_tty=0;
279                 else
280 #endif
281                         return(-1);
282                 }
283         memcpy(&(tty_new),&(tty_orig),sizeof(tty_orig));
284 #endif
285 #ifdef VMS
286         status = SYS$ASSIGN(&terminal,&channel,0,0);
287         if (status != SS$_NORMAL)
288                 return(-1);
289         status=SYS$QIOW(0,channel,IO$_SENSEMODE,&iosb,0,0,tty_orig,12,0,0,0,0);
290         if ((status != SS$_NORMAL) || (iosb.iosb$w_value != SS$_NORMAL))
291                 return(-1);
292 #endif
293
294         pushsig();
295         ps=1;
296
297 #ifdef TTY_FLAGS
298         tty_new.TTY_FLAGS &= ~ECHO;
299 #endif
300
301 #if defined(TTY_set) && !defined(VMS)
302         if (is_a_tty && (TTY_set(fileno(tty),&tty_new) == -1))
303                 return(-1);
304 #endif
305 #ifdef VMS
306         tty_new[0] = tty_orig[0];
307         tty_new[1] = tty_orig[1] | TT$M_NOECHO;
308         tty_new[2] = tty_orig[2];
309         status = SYS$QIOW(0,channel,IO$_SETMODE,&iosb,0,0,tty_new,12,0,0,0,0);
310         if ((status != SS$_NORMAL) || (iosb.iosb$w_value != SS$_NORMAL))
311                 return(-1);
312 #endif
313         ps=2;
314
315         while ((!ok) && (number--))
316                 {
317                 fputs(prompt,stderr);
318                 fflush(stderr);
319
320                 buf[0]='\0';
321                 fgets(buf,size,tty);
322                 if (feof(tty)) goto error;
323                 if (ferror(tty)) goto error;
324                 if ((p=(char *)strchr(buf,'\n')) != NULL)
325                         *p='\0';
326                 else    read_till_nl(tty);
327                 if (verify)
328                         {
329                         fprintf(stderr,"\nVerifying password - %s",prompt);
330                         fflush(stderr);
331                         buff[0]='\0';
332                         fgets(buff,size,tty);
333                         if (feof(tty)) goto error;
334                         if ((p=(char *)strchr(buff,'\n')) != NULL)
335                                 *p='\0';
336                         else    read_till_nl(tty);
337                                 
338                         if (strcmp(buf,buff) != 0)
339                                 {
340                                 fprintf(stderr,"\nVerify failure");
341                                 fflush(stderr);
342                                 break;
343                                 /* continue; */
344                                 }
345                         }
346                 ok=1;
347                 }
348
349 error:
350         fprintf(stderr,"\n");
351 #ifdef DEBUG
352         perror("fgets(tty)");
353 #endif
354         /* What can we do if there is an error? */
355 #if defined(TTY_set) && !defined(VMS) 
356         if (ps >= 2) TTY_set(fileno(tty),&tty_orig);
357 #endif
358 #ifdef VMS
359         if (ps >= 2)
360                 status = SYS$QIOW(0,channel,IO$_SETMODE,&iosb,0,0
361                         ,tty_orig,12,0,0,0,0);
362 #endif
363         
364         if (ps >= 1) popsig();
365         if (stdin != tty) fclose(tty);
366 #ifdef VMS
367         status = SYS$DASSGN(channel);
368 #endif
369         return(!ok);
370         }
371
372 #else /* WIN16 */
373
374 int des_read_pw(buf, buff, size, prompt, verify)
375 char *buf;
376 char *buff;
377 int size;
378 char *prompt;
379 int verify;
380         { 
381         memset(buf,0,size);
382         memset(buff,0,size);
383         return(0);
384         }
385
386 #endif
387
388 static void pushsig()
389         {
390         int i;
391
392         for (i=1; i<NX509_SIG; i++)
393                 {
394 #ifdef SIGUSR1
395                 if (i == SIGUSR1)
396                         continue;
397 #endif
398 #ifdef SIGUSR2
399                 if (i == SIGUSR2)
400                         continue;
401 #endif
402 #ifdef SIGACTION
403                 sigaction(i,NULL,&savsig[i]);
404 #else
405                 savsig[i]=signal(i,recsig);
406 #endif
407                 }
408
409 #ifdef SIGWINCH
410         signal(SIGWINCH,SIG_DFL);
411 #endif
412         }
413
414 static void popsig()
415         {
416         int i;
417
418         for (i=1; i<NX509_SIG; i++)
419                 {
420 #ifdef SIGUSR1
421                 if (i == SIGUSR1)
422                         continue;
423 #endif
424 #ifdef SIGUSR2
425                 if (i == SIGUSR2)
426                         continue;
427 #endif
428 #ifdef SIGACTION
429                 sigaction(i,&savsig[i],NULL);
430 #else
431                 signal(i,savsig[i]);
432 #endif
433                 }
434         }
435
436 static void recsig(i)
437 int i;
438         {
439         longjmp(save,1);
440 #ifdef LINT
441         i=i;
442 #endif
443         }
444
445 #if defined(MSDOS) && !defined(WIN16)
446 static int noecho_fgets(buf,size,tty)
447 char *buf;
448 int size;
449 FILE *tty;
450         {
451         int i;
452         char *p;
453
454         p=buf;
455         for (;;)
456                 {
457                 if (size == 0)
458                         {
459                         *p='\0';
460                         break;
461                         }
462                 size--;
463 #ifdef WIN16TTY
464                 i=_inchar();
465 #else
466                 i=getch();
467 #endif
468                 if (i == '\r') i='\n';
469                 *(p++)=i;
470                 if (i == '\n')
471                         {
472                         *p='\0';
473                         break;
474                         }
475                 }
476 #ifdef WIN_CONSOLE_BUG
477 /* Win95 has several evil console bugs: one of these is that the
478  * last character read using getch() is passed to the next read: this is
479  * usually a CR so this can be trouble. No STDIO fix seems to work but
480  * flushing the console appears to do the trick.
481  */
482                 {
483                         HANDLE inh;
484                         inh = GetStdHandle(STD_INPUT_HANDLE);
485                         FlushConsoleInputBuffer(inh);
486                 }
487 #endif
488         return(strlen(buf));
489         }
490 #endif