summaryrefslogtreecommitdiffstats
path: root/src/lib/krb5/os/promptusr.c
blob: 68f8b14a049d5dc1ec31e712a90968f9e62f9348 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*
 * promptusr.c --- prompt user for input/output
 */

#include "k5-int.h"
#if !defined(_WIN32)

#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <termios.h>
#include <signal.h>
#include <setjmp.h>

typedef struct _krb5_uio {
    krb5_magic		magic;
    int 		flags;
    char *		prompt;
    char *		response;
    struct _krb5_uio	*next;
} *krb5_uio;

#define KRB5_UIO_GETRESPONSE	0x0001
#define KRB5_UIO_ECHORESPONSE	0x0002
#define KRB5_UIO_FREE_PROMPT	0x0004

static jmp_buf pwd_jump;

static krb5_sigtype
intr_routine(int signo)
{
    longjmp(pwd_jump, 1);
    /*NOTREACHED*/
}

krb5_error_code
krb5_os_get_tty_uio(krb5_context context, krb5_uio uio)
{
    volatile krb5_error_code 	retval;
    krb5_sigtype	(*volatile ointrfunc)();
    krb5_uio		p;
    struct termios 	echo_control, save_control;
    int 		fd;
    char		read_string[BUFSIZ];
    char		*cp;
    int			ch;

    /* get the file descriptor associated with stdin */
    fd=fileno(stdin);

    if (tcgetattr(fd, &echo_control) == -1)
	return errno;

    save_control = echo_control;
    echo_control.c_lflag &= ~(ECHO|ECHONL);

    if (setjmp(pwd_jump)) {
	retval = KRB5_LIBOS_PWDINTR; 	/* we were interrupted... */
	goto cleanup;
    }
    /* save intrfunc */
    ointrfunc = signal(SIGINT, intr_routine);
    
    for (p = uio; p; p = p->next) {
	if (p->prompt) {
	    fputs(p->prompt, stdout);
	    fflush(stdout);
	}
	if ((p->flags & KRB5_UIO_GETRESPONSE) == 0)
	    continue;

	if ((p->flags & KRB5_UIO_ECHORESPONSE) == 0) 
	    if (tcsetattr(fd, TCSANOW, &echo_control) == -1)
		return errno;

	if (fgets(read_string, sizeof(read_string), stdin) == NULL) {
	    (void) putchar('\n');
	    retval = KRB5_LIBOS_CANTREADPWD;
	    goto cleanup;
	}
	
	/* replace newline with null */
	if ((cp = strchr(read_string, '\n')))
	    *cp = '\0';
	else /* flush rest of input line */
	    do {
		ch = getchar();
	    } while (ch != EOF && ch != '\n');
	read_string[sizeof(read_string)-1] = 0;

	if ((p->response = malloc(strlen(read_string)+1)) == NULL) {
	    errno = ENOMEM;
	    goto cleanup;
	}
	strcpy(p->response, read_string);

	if ((p->flags & KRB5_UIO_ECHORESPONSE) == 0) {
	    (void) putchar('\n');
	    if (tcsetattr(fd, TCSANOW, &save_control) == -1) {
		retval = errno;
		goto cleanup;
	    }
	}
    }
    retval = 0;
    
 cleanup:
    (void) signal(SIGINT, ointrfunc);
    if (retval) {
	for (p = uio; p; p = p->next) {
	    if (p->response) {
		memset(p->response, 0, strlen(p->response));
		free(p->response);
		p->response = 0;
	    }
	}
    }
    memset(read_string, 0, sizeof(read_string));
    tcsetattr(fd, TCSANOW, &save_control);
    return retval;
}

void
krb5_free_uio(krb5_context context, krb5_uio uio)
{
    krb5_uio		p, next;

    for (p = uio; p; p = next) {
	next = p->next;
	if (p->prompt && (p->flags & KRB5_UIO_FREE_PROMPT))
	    free(p->prompt);
	if (p->response)
	    free(p->response);
	free(p);
    }
}

#ifdef TEST_DRIVER

struct _krb5_uio uio_a = { 0, KRB5_UIO_GETRESPONSE, "Password 1: " };
struct _krb5_uio uio_b = { 0, KRB5_UIO_GETRESPONSE |
			       KRB5_UIO_ECHORESPONSE, "Password 2: " };
struct _krb5_uio uio_c = { 0, KRB5_UIO_GETRESPONSE, "Password 3: " };


void
main(int argc, char **argv)
{
    uio_a.next = &uio_b;
    uio_b.next = &uio_c;

    krb5_os_get_tty_uio(0, &uio_a);
    exit(0);
}

#endif
	
#endif /* !_MSODS */