xref: /onnv-gate/usr/src/lib/gss_mechs/mech_krb5/krb5/os/prompter.c (revision 7934:6aeeafc994de)
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