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