1/* vi: set sw=4 ts=4: */
2/*
3 * Ask for a password
4 * I use a static buffer in this function.  Plan accordingly.
5 *
6 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 */
10
11#include "libbb.h"
12
13/* do nothing signal handler */
14static void askpass_timeout(int UNUSED_PARAM ignore)
15{
16}
17
18char* FAST_FUNC bb_ask_stdin(const char *prompt)
19{
20	return bb_ask(STDIN_FILENO, 0, prompt);
21}
22char* FAST_FUNC bb_ask(const int fd, int timeout, const char *prompt)
23{
24	/* Was static char[BIGNUM] */
25	enum { sizeof_passwd = 128 };
26	static char *passwd;
27
28	char *ret;
29	int i;
30	struct sigaction sa, oldsa;
31	struct termios tio, oldtio;
32
33	tcgetattr(fd, &oldtio);
34	tcflush(fd, TCIFLUSH);
35	tio = oldtio;
36#ifndef IUCLC
37# define IUCLC 0
38#endif
39	tio.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY);
40	tio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP);
41	tcsetattr(fd, TCSANOW, &tio);
42
43	memset(&sa, 0, sizeof(sa));
44	/* sa.sa_flags = 0; - no SA_RESTART! */
45	/* SIGINT and SIGALRM will interrupt reads below */
46	sa.sa_handler = askpass_timeout;
47	sigaction(SIGINT, &sa, &oldsa);
48	if (timeout) {
49		sigaction_set(SIGALRM, &sa);
50		alarm(timeout);
51	}
52
53	fputs(prompt, stdout);
54	fflush_all();
55
56	if (!passwd)
57		passwd = xmalloc(sizeof_passwd);
58	ret = passwd;
59	i = 0;
60	while (1) {
61		int r = read(fd, &ret[i], 1);
62		if (r < 0) {
63			/* read is interrupted by timeout or ^C */
64			ret = NULL;
65			break;
66		}
67		if (r == 0 /* EOF */
68		 || ret[i] == '\r' || ret[i] == '\n' /* EOL */
69		 || ++i == sizeof_passwd-1 /* line limit */
70		) {
71			ret[i] = '\0';
72			break;
73		}
74	}
75
76	if (timeout) {
77		alarm(0);
78	}
79	sigaction_set(SIGINT, &oldsa);
80	tcsetattr(fd, TCSANOW, &oldtio);
81	bb_putchar('\n');
82	fflush_all();
83	return ret;
84}
85