1 /*
2  * promptusr.c --- prompt user for input/output
3  */
4 
5 #include <k5-int.h>
6 #if !defined(_WIN32)
7 
8 #include <stdio.h>
9 #include <stdlib.h>
10 #ifdef HAVE_UNISTD_H
11 #include <unistd.h>
12 #endif
13 #include <termios.h>
14 #include <signal.h>
15 #include <setjmp.h>
16 
17 typedef struct _krb5_uio {
18     krb5_magic		magic;
19     int 		flags;
20     char *		prompt;
21     char *		response;
22     struct _krb5_uio	*next;
23 } *krb5_uio;
24 
25 #define KRB5_UIO_GETRESPONSE	0x0001
26 #define KRB5_UIO_ECHORESPONSE	0x0002
27 #define KRB5_UIO_FREE_PROMPT	0x0004
28 
29 static jmp_buf pwd_jump;
30 
31 /*ARGSUSED*/
32 static krb5_sigtype
intr_routine(int signo)33 intr_routine(int signo)
34 {
35     longjmp(pwd_jump, 1);
36     /*NOTREACHED*/
37 }
38 
39 /*ARGSUSED*/
40 krb5_error_code
krb5_os_get_tty_uio(krb5_context context,krb5_uio uio)41 krb5_os_get_tty_uio(krb5_context context, krb5_uio uio)
42 {
43     volatile krb5_error_code 	retval;
44     krb5_sigtype	(*volatile ointrfunc)();
45     krb5_uio		p;
46     struct termios 	echo_control, save_control;
47     int 		fd;
48     char		read_string[BUFSIZ];
49     char		*cp;
50     int			ch;
51 
52     /* get the file descriptor associated with stdin */
53     fd=fileno(stdin);
54 
55     if (tcgetattr(fd, &echo_control) == -1)
56 	return errno;
57 
58     save_control = echo_control;
59     echo_control.c_lflag &= ~(ECHO|ECHONL);
60 
61     if (setjmp(pwd_jump)) {
62 	retval = KRB5_LIBOS_PWDINTR; 	/* we were interrupted... */
63 	goto cleanup;
64     }
65     /* save intrfunc */
66     ointrfunc = signal(SIGINT, intr_routine);
67 
68     for (p = uio; p; p = p->next) {
69 	if (p->prompt) {
70 	    fputs(p->prompt, stdout);
71 	    fflush(stdout);
72 	}
73 	if ((p->flags & KRB5_UIO_GETRESPONSE) == 0)
74 	    continue;
75 
76 	if ((p->flags & KRB5_UIO_ECHORESPONSE) == 0)
77 	    if (tcsetattr(fd, TCSANOW, &echo_control) == -1)
78 		return errno;
79 
80 	if (fgets(read_string, sizeof(read_string), stdin) == NULL) {
81 	    (void) putchar('\n');
82 	    retval = KRB5_LIBOS_CANTREADPWD;
83 	    goto cleanup;
84 	}
85 
86 	/* replace newline with null */
87 	if ((cp = strchr(read_string, '\n')))
88 	    *cp = '\0';
89 	else /* flush rest of input line */
90 	    do {
91 		ch = getchar();
92 	    } while (ch != EOF && ch != '\n');
93 	read_string[sizeof(read_string)-1] = 0;
94 
95 	if ((p->response = malloc(strlen(read_string)+1)) == NULL) {
96 	    errno = ENOMEM;
97 	    goto cleanup;
98 	}
99 	strcpy(p->response, read_string);
100 
101 	if ((p->flags & KRB5_UIO_ECHORESPONSE) == 0) {
102 	    (void) putchar('\n');
103 	    if (tcsetattr(fd, TCSANOW, &save_control) == -1) {
104 		retval = errno;
105 		goto cleanup;
106 	    }
107 	}
108     }
109     retval = 0;
110 
111  cleanup:
112     (void) signal(SIGINT, ointrfunc);
113     if (retval) {
114 	for (p = uio; p; p = p->next) {
115 	    if (p->response) {
116 		memset(p->response, 0, strlen(p->response));
117 		free(p->response);
118 		p->response = 0;
119 	    }
120 	}
121     }
122     memset(read_string, 0, sizeof(read_string));
123     tcsetattr(fd, TCSANOW, &save_control);
124     return retval;
125 }
126 
127 /*ARGSUSED*/
128 void
krb5_free_uio(krb5_context context,krb5_uio uio)129 krb5_free_uio(krb5_context context, krb5_uio uio)
130 {
131     krb5_uio		p, next;
132 
133     for (p = uio; p; p = next) {
134 	next = p->next;
135 	if (p->prompt && (p->flags & KRB5_UIO_FREE_PROMPT))
136 	    free(p->prompt);
137 	if (p->response)
138 	    free(p->response);
139 	free(p);
140     }
141 }
142 
143 #ifdef TEST_DRIVER
144 
145 struct _krb5_uio uio_a = { 0, KRB5_UIO_GETRESPONSE, "Password 1: " };
146 struct _krb5_uio uio_b = { 0, KRB5_UIO_GETRESPONSE |
147 			       KRB5_UIO_ECHORESPONSE, "Password 2: " };
148 struct _krb5_uio uio_c = { 0, KRB5_UIO_GETRESPONSE, "Password 3: " };
149 
150 
151 void
main(int argc,char ** argv)152 main(int argc, char **argv)
153 {
154     uio_a.next = &uio_b;
155     uio_b.next = &uio_c;
156 
157     krb5_os_get_tty_uio(0, &uio_a);
158     exit(0);
159 }
160 
161 #endif
162 
163 #endif /* !_MSODS */
164