1*7934SMark.Phalan@Sun.COM #include "k5-int.h"
2*7934SMark.Phalan@Sun.COM #if !defined(_WIN32) || (defined(_WIN32) && defined(__CYGWIN32__))
30Sstevel@tonic-gate #include <stdio.h>
40Sstevel@tonic-gate #include <errno.h>
50Sstevel@tonic-gate #include <signal.h>
60Sstevel@tonic-gate #include <limits.h>
70Sstevel@tonic-gate /* Is vxworks broken w.r.t. termios? --tlyu */
80Sstevel@tonic-gate #ifdef __vxworks
90Sstevel@tonic-gate #define ECHO_PASSWORD
100Sstevel@tonic-gate #endif
110Sstevel@tonic-gate
120Sstevel@tonic-gate #include <termios.h>
130Sstevel@tonic-gate
140Sstevel@tonic-gate #ifdef POSIX_SIGNALS
150Sstevel@tonic-gate typedef struct sigaction osiginfo;
160Sstevel@tonic-gate #else
170Sstevel@tonic-gate typedef struct krb5_sigtype (*osiginfo)();
180Sstevel@tonic-gate #endif
190Sstevel@tonic-gate
200Sstevel@tonic-gate static void catch_signals(osiginfo *);
210Sstevel@tonic-gate static void restore_signals(osiginfo *);
220Sstevel@tonic-gate static krb5_sigtype intrfunc(int sig);
230Sstevel@tonic-gate
240Sstevel@tonic-gate static krb5_error_code setup_tty(FILE*, int, struct termios *, osiginfo *);
250Sstevel@tonic-gate static krb5_error_code restore_tty(FILE*, struct termios *, osiginfo *);
260Sstevel@tonic-gate
270Sstevel@tonic-gate static volatile int got_int; /* should be sig_atomic_t */
280Sstevel@tonic-gate
290Sstevel@tonic-gate krb5_error_code KRB5_CALLCONV
krb5_prompter_posix(krb5_context context,void * data,const char * name,const char * banner,int num_prompts,krb5_prompt prompts[])300Sstevel@tonic-gate krb5_prompter_posix(
310Sstevel@tonic-gate krb5_context context,
320Sstevel@tonic-gate void *data,
330Sstevel@tonic-gate const char *name,
340Sstevel@tonic-gate const char *banner,
350Sstevel@tonic-gate int num_prompts,
360Sstevel@tonic-gate krb5_prompt prompts[])
370Sstevel@tonic-gate {
380Sstevel@tonic-gate int fd, i, scratchchar;
390Sstevel@tonic-gate FILE *fp;
400Sstevel@tonic-gate char *retp;
410Sstevel@tonic-gate krb5_error_code errcode;
420Sstevel@tonic-gate struct termios saveparm;
430Sstevel@tonic-gate osiginfo osigint;
440Sstevel@tonic-gate
450Sstevel@tonic-gate errcode = KRB5_LIBOS_CANTREADPWD;
460Sstevel@tonic-gate
470Sstevel@tonic-gate if (name) {
480Sstevel@tonic-gate fputs(name, stdout);
490Sstevel@tonic-gate fputs("\n", stdout);
500Sstevel@tonic-gate }
510Sstevel@tonic-gate if (banner) {
520Sstevel@tonic-gate fputs(banner, stdout);
530Sstevel@tonic-gate fputs("\n", stdout);
540Sstevel@tonic-gate }
550Sstevel@tonic-gate
560Sstevel@tonic-gate /*
570Sstevel@tonic-gate * Get a non-buffered stream on stdin.
580Sstevel@tonic-gate */
590Sstevel@tonic-gate fp = NULL;
600Sstevel@tonic-gate fd = dup(STDIN_FILENO);
610Sstevel@tonic-gate if (fd < 0)
620Sstevel@tonic-gate return KRB5_LIBOS_CANTREADPWD;
630Sstevel@tonic-gate fp = fdopen(fd, "r");
640Sstevel@tonic-gate if (fp == NULL)
650Sstevel@tonic-gate goto cleanup;
660Sstevel@tonic-gate if (setvbuf(fp, NULL, _IONBF, 0))
670Sstevel@tonic-gate goto cleanup;
680Sstevel@tonic-gate
690Sstevel@tonic-gate for (i = 0; i < num_prompts; i++) {
700Sstevel@tonic-gate errcode = KRB5_LIBOS_CANTREADPWD;
710Sstevel@tonic-gate /* fgets() takes int, but krb5_data.length is unsigned. */
720Sstevel@tonic-gate if (prompts[i].reply->length > INT_MAX)
730Sstevel@tonic-gate goto cleanup;
740Sstevel@tonic-gate
750Sstevel@tonic-gate errcode = setup_tty(fp, prompts[i].hidden, &saveparm, &osigint);
760Sstevel@tonic-gate if (errcode)
770Sstevel@tonic-gate break;
780Sstevel@tonic-gate
790Sstevel@tonic-gate /* put out the prompt */
800Sstevel@tonic-gate (void)fputs(prompts[i].prompt, stdout);
810Sstevel@tonic-gate (void)fputs(": ", stdout);
820Sstevel@tonic-gate (void)fflush(stdout);
830Sstevel@tonic-gate (void)memset(prompts[i].reply->data, 0, prompts[i].reply->length);
840Sstevel@tonic-gate
850Sstevel@tonic-gate got_int = 0;
860Sstevel@tonic-gate retp = fgets(prompts[i].reply->data, (int)prompts[i].reply->length,
870Sstevel@tonic-gate fp);
880Sstevel@tonic-gate if (prompts[i].hidden)
890Sstevel@tonic-gate putchar('\n');
900Sstevel@tonic-gate if (retp == NULL) {
910Sstevel@tonic-gate if (got_int)
920Sstevel@tonic-gate errcode = KRB5_LIBOS_PWDINTR;
930Sstevel@tonic-gate else
940Sstevel@tonic-gate errcode = KRB5_LIBOS_CANTREADPWD;
950Sstevel@tonic-gate restore_tty(fp, &saveparm, &osigint);
960Sstevel@tonic-gate break;
970Sstevel@tonic-gate }
980Sstevel@tonic-gate
990Sstevel@tonic-gate /* replace newline with null */
1000Sstevel@tonic-gate retp = strchr(prompts[i].reply->data, '\n');
1010Sstevel@tonic-gate if (retp != NULL)
1020Sstevel@tonic-gate *retp = '\0';
1030Sstevel@tonic-gate else {
1040Sstevel@tonic-gate /* flush rest of input line */
1050Sstevel@tonic-gate do {
1060Sstevel@tonic-gate scratchchar = getc(fp);
1070Sstevel@tonic-gate } while (scratchchar != EOF && scratchchar != '\n');
1080Sstevel@tonic-gate }
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate errcode = restore_tty(fp, &saveparm, &osigint);
1110Sstevel@tonic-gate if (errcode)
1120Sstevel@tonic-gate break;
1130Sstevel@tonic-gate prompts[i].reply->length = strlen(prompts[i].reply->data);
1140Sstevel@tonic-gate }
1150Sstevel@tonic-gate cleanup:
1160Sstevel@tonic-gate if (fp != NULL)
1170Sstevel@tonic-gate fclose(fp);
1180Sstevel@tonic-gate else if (fd >= 0)
1190Sstevel@tonic-gate close(fd);
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate return errcode;
1220Sstevel@tonic-gate }
1230Sstevel@tonic-gate
intrfunc(int sig)1240Sstevel@tonic-gate static krb5_sigtype intrfunc(int sig)
1250Sstevel@tonic-gate {
1260Sstevel@tonic-gate got_int = 1;
1270Sstevel@tonic-gate }
1280Sstevel@tonic-gate
1290Sstevel@tonic-gate static void
catch_signals(osiginfo * osigint)1300Sstevel@tonic-gate catch_signals(osiginfo *osigint)
1310Sstevel@tonic-gate {
1320Sstevel@tonic-gate #ifdef POSIX_SIGNALS
1330Sstevel@tonic-gate struct sigaction sa;
1340Sstevel@tonic-gate
1350Sstevel@tonic-gate sigemptyset(&sa.sa_mask);
1360Sstevel@tonic-gate sa.sa_flags = 0;
1370Sstevel@tonic-gate sa.sa_handler = intrfunc;
1380Sstevel@tonic-gate sigaction(SIGINT, &sa, osigint);
1390Sstevel@tonic-gate #else
1400Sstevel@tonic-gate *osigint = signal(SIGINT, intrfunc);
1410Sstevel@tonic-gate #endif
1420Sstevel@tonic-gate }
1430Sstevel@tonic-gate
1440Sstevel@tonic-gate static void
restore_signals(osiginfo * osigint)1450Sstevel@tonic-gate restore_signals(osiginfo *osigint)
1460Sstevel@tonic-gate {
1470Sstevel@tonic-gate #ifdef POSIX_SIGNALS
1480Sstevel@tonic-gate sigaction(SIGINT, osigint, NULL);
1490Sstevel@tonic-gate #else
1500Sstevel@tonic-gate signal(SIGINT, *osigint);
1510Sstevel@tonic-gate #endif
1520Sstevel@tonic-gate }
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate static krb5_error_code
setup_tty(FILE * fp,int hidden,struct termios * saveparm,osiginfo * osigint)1550Sstevel@tonic-gate setup_tty(FILE *fp, int hidden, struct termios *saveparm, osiginfo *osigint)
1560Sstevel@tonic-gate {
1570Sstevel@tonic-gate krb5_error_code ret;
1580Sstevel@tonic-gate int fd;
1590Sstevel@tonic-gate struct termios tparm;
1600Sstevel@tonic-gate
1610Sstevel@tonic-gate ret = KRB5_LIBOS_CANTREADPWD;
1620Sstevel@tonic-gate catch_signals(osigint);
1630Sstevel@tonic-gate fd = fileno(fp);
1640Sstevel@tonic-gate do {
1650Sstevel@tonic-gate if (!isatty(fd)) {
1660Sstevel@tonic-gate ret = 0;
1670Sstevel@tonic-gate break;
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate if (tcgetattr(fd, &tparm) < 0)
1700Sstevel@tonic-gate break;
1710Sstevel@tonic-gate *saveparm = tparm;
1720Sstevel@tonic-gate #ifndef ECHO_PASSWORD
1730Sstevel@tonic-gate if (hidden)
1740Sstevel@tonic-gate tparm.c_lflag &= ~(ECHO|ECHONL);
1750Sstevel@tonic-gate #endif
1760Sstevel@tonic-gate tparm.c_lflag |= ISIG|ICANON;
1770Sstevel@tonic-gate if (tcsetattr(STDIN_FILENO, TCSANOW, &tparm) < 0)
1780Sstevel@tonic-gate break;
1790Sstevel@tonic-gate ret = 0;
1800Sstevel@tonic-gate } while (0);
1810Sstevel@tonic-gate /* If we're losing, restore signal handlers. */
1820Sstevel@tonic-gate if (ret)
1830Sstevel@tonic-gate restore_signals(osigint);
1840Sstevel@tonic-gate return ret;
1850Sstevel@tonic-gate }
1860Sstevel@tonic-gate
1870Sstevel@tonic-gate static krb5_error_code
restore_tty(FILE * fp,struct termios * saveparm,osiginfo * osigint)1880Sstevel@tonic-gate restore_tty(FILE* fp, struct termios *saveparm, osiginfo *osigint)
1890Sstevel@tonic-gate {
1900Sstevel@tonic-gate int ret, fd;
1910Sstevel@tonic-gate
1920Sstevel@tonic-gate ret = 0;
1930Sstevel@tonic-gate fd = fileno(fp);
1940Sstevel@tonic-gate if (isatty(fd)) {
1950Sstevel@tonic-gate ret = tcsetattr(fd, TCSANOW, saveparm);
1960Sstevel@tonic-gate if (ret < 0)
1970Sstevel@tonic-gate ret = KRB5_LIBOS_CANTREADPWD;
1980Sstevel@tonic-gate else
1990Sstevel@tonic-gate ret = 0;
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate restore_signals(osigint);
2020Sstevel@tonic-gate return ret;
2030Sstevel@tonic-gate }
2040Sstevel@tonic-gate
2050Sstevel@tonic-gate #else /* non-Cygwin Windows, or Mac */
2060Sstevel@tonic-gate
2070Sstevel@tonic-gate #if defined(_WIN32)
2080Sstevel@tonic-gate
2090Sstevel@tonic-gate #include <io.h>
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate krb5_error_code KRB5_CALLCONV
krb5_prompter_posix(krb5_context context,void * data,const char * name,const char * banner,int num_prompts,krb5_prompt prompts[])2120Sstevel@tonic-gate krb5_prompter_posix(krb5_context context,
2130Sstevel@tonic-gate void *data,
2140Sstevel@tonic-gate const char *name,
2150Sstevel@tonic-gate const char *banner,
2160Sstevel@tonic-gate int num_prompts,
2170Sstevel@tonic-gate krb5_prompt prompts[])
2180Sstevel@tonic-gate {
2190Sstevel@tonic-gate HANDLE handle;
2200Sstevel@tonic-gate DWORD old_mode, new_mode;
2210Sstevel@tonic-gate char *ptr;
2220Sstevel@tonic-gate int scratchchar;
2230Sstevel@tonic-gate krb5_error_code errcode = 0;
2240Sstevel@tonic-gate int i;
2250Sstevel@tonic-gate
2260Sstevel@tonic-gate handle = GetStdHandle(STD_INPUT_HANDLE);
2270Sstevel@tonic-gate if (handle == INVALID_HANDLE_VALUE)
2280Sstevel@tonic-gate return ENOTTY;
2290Sstevel@tonic-gate if (!GetConsoleMode(handle, &old_mode))
2300Sstevel@tonic-gate return ENOTTY;
2310Sstevel@tonic-gate
2320Sstevel@tonic-gate new_mode = old_mode;
2330Sstevel@tonic-gate new_mode |= ( ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT );
2340Sstevel@tonic-gate new_mode &= ~( ENABLE_ECHO_INPUT );
2350Sstevel@tonic-gate
2360Sstevel@tonic-gate if (!SetConsoleMode(handle, new_mode))
2370Sstevel@tonic-gate return ENOTTY;
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate if (!SetConsoleMode(handle, old_mode))
2400Sstevel@tonic-gate return ENOTTY;
2410Sstevel@tonic-gate
2420Sstevel@tonic-gate if (name) {
2430Sstevel@tonic-gate fputs(name, stdout);
2440Sstevel@tonic-gate fputs("\n", stdout);
2450Sstevel@tonic-gate }
2460Sstevel@tonic-gate
2470Sstevel@tonic-gate if (banner) {
2480Sstevel@tonic-gate fputs(banner, stdout);
2490Sstevel@tonic-gate fputs("\n", stdout);
2500Sstevel@tonic-gate }
2510Sstevel@tonic-gate
2520Sstevel@tonic-gate for (i = 0; i < num_prompts; i++) {
2530Sstevel@tonic-gate if (prompts[i].hidden) {
2540Sstevel@tonic-gate if (!SetConsoleMode(handle, new_mode)) {
2550Sstevel@tonic-gate errcode = ENOTTY;
2560Sstevel@tonic-gate goto cleanup;
2570Sstevel@tonic-gate }
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate
2600Sstevel@tonic-gate fputs(prompts[i].prompt,stdout);
2610Sstevel@tonic-gate fputs(": ", stdout);
2620Sstevel@tonic-gate fflush(stdout);
2630Sstevel@tonic-gate memset(prompts[i].reply->data, 0, prompts[i].reply->length);
2640Sstevel@tonic-gate
2650Sstevel@tonic-gate if (fgets(prompts[i].reply->data, prompts[i].reply->length, stdin)
2660Sstevel@tonic-gate == NULL) {
2670Sstevel@tonic-gate if (prompts[i].hidden)
2680Sstevel@tonic-gate putchar('\n');
2690Sstevel@tonic-gate errcode = KRB5_LIBOS_CANTREADPWD;
2700Sstevel@tonic-gate goto cleanup;
2710Sstevel@tonic-gate }
2720Sstevel@tonic-gate if (prompts[i].hidden)
2730Sstevel@tonic-gate putchar('\n');
2740Sstevel@tonic-gate /* fgets always null-terminates the returned string */
2750Sstevel@tonic-gate
2760Sstevel@tonic-gate /* replace newline with null */
2770Sstevel@tonic-gate if ((ptr = strchr(prompts[i].reply->data, '\n')))
2780Sstevel@tonic-gate *ptr = '\0';
2790Sstevel@tonic-gate else /* flush rest of input line */
2800Sstevel@tonic-gate do {
2810Sstevel@tonic-gate scratchchar = getchar();
2820Sstevel@tonic-gate } while (scratchchar != EOF && scratchchar != '\n');
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate prompts[i].reply->length = strlen(prompts[i].reply->data);
2850Sstevel@tonic-gate
2860Sstevel@tonic-gate if (!SetConsoleMode(handle, old_mode)) {
2870Sstevel@tonic-gate errcode = ENOTTY;
2880Sstevel@tonic-gate goto cleanup;
2890Sstevel@tonic-gate }
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate cleanup:
2930Sstevel@tonic-gate if (errcode) {
2940Sstevel@tonic-gate for (i = 0; i < num_prompts; i++) {
2950Sstevel@tonic-gate memset(prompts[i].reply->data, 0, prompts[i].reply->length);
2960Sstevel@tonic-gate }
2970Sstevel@tonic-gate }
2980Sstevel@tonic-gate return errcode;
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate
3010Sstevel@tonic-gate #else /* !_WIN32 */
3020Sstevel@tonic-gate
3030Sstevel@tonic-gate krb5_error_code KRB5_CALLCONV
krb5_prompter_posix(krb5_context context,void * data,const char * name,const char * banner,int num_prompts,krb5_prompt prompts[])3040Sstevel@tonic-gate krb5_prompter_posix(krb5_context context,
3050Sstevel@tonic-gate void *data,
3060Sstevel@tonic-gate const char *name,
3070Sstevel@tonic-gate const char *banner,
3080Sstevel@tonic-gate int num_prompts,
3090Sstevel@tonic-gate krb5_prompt prompts[])
3100Sstevel@tonic-gate {
3110Sstevel@tonic-gate return(EINVAL);
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate #endif /* !_WIN32 */
3140Sstevel@tonic-gate #endif /* Windows or Mac */
3150Sstevel@tonic-gate
3160Sstevel@tonic-gate void
krb5int_set_prompt_types(krb5_context context,krb5_prompt_type * types)3170Sstevel@tonic-gate krb5int_set_prompt_types(krb5_context context, krb5_prompt_type *types)
3180Sstevel@tonic-gate {
3190Sstevel@tonic-gate context->prompt_types = types;
3200Sstevel@tonic-gate }
3210Sstevel@tonic-gate
3220Sstevel@tonic-gate krb5_prompt_type*
3230Sstevel@tonic-gate KRB5_CALLCONV
krb5_get_prompt_types(krb5_context context)3240Sstevel@tonic-gate krb5_get_prompt_types(krb5_context context)
3250Sstevel@tonic-gate {
3260Sstevel@tonic-gate return context->prompt_types;
3270Sstevel@tonic-gate }
328