#define __EXTENSIONS__
#include <errno.h>
#include <libgen.h>
#include <malloc.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <stropts.h>
#include <unistd.h>
#include <termio.h>
#include <security/pam_appl.h>
static int ctl_c;
static void
interrupt(int x)
{
ctl_c = 1;
}
static char *
getinput(int noecho)
{
struct termio tty;
unsigned short tty_flags = 0;
char input[PAM_MAX_RESP_SIZE + 1];
int c;
int i = 0;
void (*sig)(int);
ctl_c = 0;
sig = signal(SIGINT, interrupt);
if (noecho) {
(void) ioctl(fileno(stdin), TCGETA, &tty);
tty_flags = tty.c_lflag;
tty.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
(void) ioctl(fileno(stdin), TCSETAF, &tty);
}
flockfile(stdin);
while (ctl_c == 0 &&
(c = getchar_unlocked()) != '\n' &&
c != '\r' &&
c != EOF) {
if (i < PAM_MAX_RESP_SIZE) {
input[i++] = (char)c;
}
}
funlockfile(stdin);
input[i] = '\0';
if (noecho) {
tty.c_lflag = tty_flags;
(void) ioctl(fileno(stdin), TCSETAW, &tty);
(void) fputc('\n', stdout);
}
(void) signal(SIGINT, sig);
if (ctl_c == 1)
(void) kill(getpid(), SIGINT);
return (strdup(input));
}
static void
free_resp(int num_msg, struct pam_response *pr)
{
int i;
struct pam_response *r = pr;
if (pr == NULL)
return;
for (i = 0; i < num_msg; i++, r++) {
if (r->resp) {
bzero(r->resp, strlen(r->resp));
free(r->resp);
r->resp = NULL;
}
}
free(pr);
}
int
pam_tty_conv(int num_msg, const struct pam_message **mess,
struct pam_response **resp, void *my_data)
{
const struct pam_message *m = *mess;
struct pam_response *r = calloc(num_msg, sizeof (struct pam_response));
int i;
if (num_msg >= PAM_MAX_NUM_MSG) {
(void) fprintf(stderr, "too many messages %d >= %d\n",
num_msg, PAM_MAX_NUM_MSG);
free(r);
*resp = NULL;
return (PAM_CONV_ERR);
}
*resp = r;
for (i = 0; i < num_msg; i++) {
int echo_off;
if (m->msg == NULL) {
(void) fprintf(stderr, "message[%d]: %d/NULL\n",
i, m->msg_style);
goto err;
}
if (m->msg[strlen(m->msg)] == '\n')
m->msg[strlen(m->msg)] = '\0';
r->resp = NULL;
r->resp_retcode = 0;
echo_off = 0;
switch (m->msg_style) {
case PAM_PROMPT_ECHO_OFF:
echo_off = 1;
case PAM_PROMPT_ECHO_ON:
(void) fputs(m->msg, stdout);
r->resp = getinput(echo_off);
break;
case PAM_ERROR_MSG:
(void) fputs(m->msg, stderr);
(void) fputc('\n', stderr);
break;
case PAM_TEXT_INFO:
(void) fputs(m->msg, stdout);
(void) fputc('\n', stdout);
break;
default:
(void) fprintf(stderr, "message[%d]: unknown type "
"%d/val=\"%s\"\n",
i, m->msg_style, m->msg);
goto err;
}
if (errno == EINTR)
goto err;
m++;
r++;
}
return (PAM_SUCCESS);
err:
free_resp(i, r);
*resp = NULL;
return (PAM_CONV_ERR);
}