1/*
2 * Copyright (c) 2011-12 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 * Copyright (c) 1997 - 2000, 2005 Kungliga Tekniska Högskolan
26 * (Royal Institute of Technology, Stockholm, Sweden).
27 * All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 *
33 * 1. Redistributions of source code must retain the above copyright
34 *    notice, this list of conditions and the following disclaimer.
35 *
36 * 2. Redistributions in binary form must reproduce the above copyright
37 *    notice, this list of conditions and the following disclaimer in the
38 *    documentation and/or other materials provided with the distribution.
39 *
40 * 3. Neither the name of the Institute nor the names of its contributors
41 *    may be used to endorse or promote products derived from this software
42 *    without specific prior written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
55 */
56
57#include "ossl-config.h"
58
59#include <fcntl.h>
60#include <stdio.h>
61#include <stdlib.h>
62#include <string.h>
63#include <signal.h>
64#ifdef HAVE_TERMIOS_H
65#include <termios.h>
66#endif
67
68#include "ossl-ui.h"
69
70#ifdef HAVE_CONIO_H
71#include <conio.h>
72#endif
73
74static sig_atomic_t intr_flag;
75
76static void
77intr(int sig)
78{
79	intr_flag++;
80}
81
82
83#ifdef HAVE_CONIO_H
84
85/*
86 * Windows does console slightly different then then unix case.
87 */
88static int
89read_string(const char *preprompt, const char *prompt,
90    char *buf, size_t len, int echo)
91{
92	int of = 0;
93	int c;
94	char *p;
95
96	void (*oldsigintr)(int);
97
98	_cprintf("%s%s", preprompt, prompt);
99
100	oldsigintr = signal(SIGINT, intr);
101
102	p = buf;
103	while (intr_flag == 0) {
104		c = ((echo) ? _getche() : _getch());
105		if ((c == '\n') || (c == '\r')) {
106			break;
107		}
108		if (of == 0) {
109			*p++ = c;
110		}
111		of = (p == buf + len);
112	}
113	if (of) {
114		p--;
115	}
116	*p = 0;
117
118	if (echo == 0) {
119		printf("\n");
120	}
121
122	signal(SIGINT, oldsigintr);
123
124	if (intr_flag) {
125		return (-2);
126	}
127	if (of) {
128		return (-1);
129	}
130	return (0);
131}
132
133
134#else /* !HAVE_CONIO_H */
135
136#ifndef NSIG
137#define NSIG			47
138#endif
139
140#define FLAG_ECHO		1
141#define FLAG_USE_STDIO		2
142
143
144static int
145read_string(const char *preprompt, const char *prompt,
146    char *buf, size_t len, int flags)
147{
148	struct sigaction sigs[NSIG];
149	int oksigs[NSIG];
150	struct sigaction sa;
151	FILE *tty;
152	int ret = 0;
153	int of = 0;
154	int i;
155	int c;
156	char *p;
157
158	struct termios t_new, t_old;
159
160	memset(&oksigs, 0, sizeof(oksigs));
161
162	memset(&sa, 0, sizeof(sa));
163	sa.sa_handler = intr;
164	sigemptyset(&sa.sa_mask);
165	sa.sa_flags = 0;
166	for (i = 1; i < sizeof(sigs) / sizeof(sigs[0]); i++) {
167		if (i != SIGALRM) {
168			if (sigaction(i, &sa, &sigs[i]) == 0) {
169				oksigs[i] = 1;
170			}
171		}
172	}
173
174	/*
175	 * Don't use /dev/tty for now since server tools want to to
176	 * read/write from stdio when setting up and interacting with the
177	 * Kerberos subsystem.
178	 *
179	 * When <rdar://problem/7308846> is in we can remove this, this is
180	 * to make transiation easier for server folks.
181	 */
182	if ((flags & FLAG_USE_STDIO) != 0) {
183		tty = stdin;
184	} else if ((tty = fopen("/dev/tty", "r")) != NULL) {
185		int flg, fd = fileno(tty);
186		/* rk_cloexec_file(tty); */
187		if ((flg = fcntl(fd, F_GETFD)) != -1) {
188			fcntl(fd, F_SETFD, flg | FD_CLOEXEC);
189		}
190	} else{
191		tty = stdin;
192	}
193
194	fprintf(stderr, "%s%s", preprompt, prompt);
195	fflush(stderr);
196
197	if ((flags & FLAG_ECHO) == 0) {
198		tcgetattr(fileno(tty), &t_old);
199		memcpy(&t_new, &t_old, sizeof(t_new));
200		t_new.c_lflag &= ~ECHO;
201		tcsetattr(fileno(tty), TCSANOW, &t_new);
202	}
203	intr_flag = 0;
204	p = buf;
205	while (intr_flag == 0) {
206		c = getc(tty);
207		if (c == EOF) {
208			if (!ferror(tty)) {
209				ret = 1;
210			}
211			break;
212		}
213		if (c == '\n') {
214			break;
215		}
216		if (of == 0) {
217			*p++ = c;
218		}
219		of = (p == buf + len);
220	}
221	if (of) {
222		p--;
223	}
224	*p = 0;
225
226	if ((flags & FLAG_ECHO) == 0) {
227		fprintf(stderr, "\n");
228		tcsetattr(fileno(tty), TCSANOW, &t_old);
229	}
230
231	if (tty != stdin) {
232		fclose(tty);
233	}
234
235	for (i = 1; i < sizeof(sigs) / sizeof(sigs[0]); i++) {
236		if (oksigs[i]) {
237			sigaction(i, &sigs[i], NULL);
238		}
239	}
240
241	if (ret) {
242		return (-3);
243	}
244	if (intr_flag) {
245		return (-2);
246	}
247	if (of) {
248		return (-1);
249	}
250	return (0);
251}
252
253
254#endif /* HAVE_CONIO_H */
255
256int
257UI_UTIL_read_pw_string(char *buf, int length, const char *prompt, int verify)
258{
259	int ret;
260
261	ret = read_string("", prompt, buf, length, 0);
262	if (ret) {
263		return (ret);
264	}
265
266	if (verify) {
267		char *buf2;
268		buf2 = malloc(length);
269		if (buf2 == NULL) {
270			return (1);
271		}
272
273		ret = read_string("Verify password - ", prompt, buf2, length, 0);
274		if (ret) {
275			free(buf2);
276			return (ret);
277		}
278		if (strcmp(buf2, buf) != 0) {
279			ret = 1;
280		}
281		memset(buf2, 0, length);
282		free(buf2);
283	}
284	return (ret);
285}
286
287
288int
289UI_UTIL_read_pw_string_stdio(char *buf, int length, const char *prompt, int verify)
290{
291	int ret;
292
293	ret = read_string("", prompt, buf, length, FLAG_USE_STDIO);
294	if (ret) {
295		return (ret);
296	}
297
298	if (verify) {
299		char *buf2;
300		buf2 = malloc(length);
301		if (buf2 == NULL) {
302			return (1);
303		}
304
305		ret = read_string("Verify password - ", prompt, buf2, length, FLAG_USE_STDIO);
306		if (ret) {
307			free(buf2);
308			return (ret);
309		}
310		if (strcmp(buf2, buf) != 0) {
311			ret = 1;
312		}
313		memset(buf2, 0, length);
314		free(buf2);
315	}
316	return (ret);
317}
318