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 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
|
/* PlanC (hubenchang0515@outlook.com) -- an example application
* that implements a custom conversation */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <termios.h>
#include <security/pam_appl.h>
#include <sys/ioctl.h>
/***************************************
* @brief echo off/on
* @param[in] fd file descriptor
* @param[in] off 1 - echo off,0 - echo on
***************************************/
static void echoOff(int fd, int off)
{
struct termios tty;
if (ioctl(fd, TCGETA, &tty) < 0)
{
fprintf(stderr, "TCGETA failed: %s\n", strerror(errno));
return;
}
if (off)
{
tty.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
if (ioctl(fd, TCSETAF, &tty) < 0)
{
fprintf(stderr, "TCSETAF failed: %s\n", strerror(errno));
}
}
else
{
tty.c_lflag |= (ECHO | ECHOE | ECHOK | ECHONL);
if (ioctl(fd, TCSETAW, &tty) < 0)
{
fprintf(stderr, "TCSETAW failed: %s\n", strerror(errno));
}
}
}
/***************************************
* @brief echo off stdin
***************************************/
static void echoOffStdin(void)
{
echoOff(fileno(stdin), 1);
}
/***************************************
* @brief echo on stdin
***************************************/
static void echoOnStdin(void)
{
echoOff(fileno(stdin), 0);
}
/***************************************
* @brief read a line input
* @return the input string
***************************************/
static char *readline(void)
{
char input[PAM_MAX_RESP_SIZE];
int i;
flockfile(stdin);
for (i = 0; i < PAM_MAX_RESP_SIZE - 1; i++)
{
int ch = getchar_unlocked();
if (ch == '\n' || ch == '\r' ||ch == EOF)
break;
input[i] = ch;
}
funlockfile(stdin);
input[i] = '\0';
return (strdup(input));
}
/**************************************************
* @brief callback of PAM conversation
* @param[in] num_msg the count of message
* @param[in] msg PAM message
* @param[out] resp our response
* @param[in] appdata_ptr custom data passed by struct pam_conv.appdata_ptr
* @return state
**************************************************/
static int conversation(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
{
(void)(appdata_ptr);
int i;
/* check the count of message */
if (num_msg <= 0 || num_msg >= PAM_MAX_MSG_SIZE)
{
fprintf(stderr, "invalid num_msg(%d)\n", num_msg);
return PAM_CONV_ERR;
}
/* alloc memory for response */
if ((resp[0] = malloc(num_msg * sizeof(struct pam_response))) == NULL)
{
fprintf(stderr, "bad alloc\n");
return PAM_BUF_ERR;
}
/* response for message */
for (i = 0; i < num_msg; i++)
{
const struct pam_message *m = *msg + i;
struct pam_response *r = *resp + i;
r->resp_retcode = 0; /* currently un-used, zero expected */
switch (m->msg_style)
{
case PAM_PROMPT_ECHO_OFF: /* get the input with echo off, like the password */
printf("%s", m->msg);
echoOffStdin();
r->resp = readline();
echoOnStdin();
printf("\n");
break;
case PAM_PROMPT_ECHO_ON: /* get the input with echo on, like the username */
printf("%s", m->msg);
r->resp = readline();
break;
case PAM_TEXT_INFO: /* normal info */
printf("%s\n", m->msg);
break;
case PAM_ERROR_MSG: /* error info */
fprintf(stderr, "%s\n", m->msg);
break;
default:
fprintf(stderr, "unexpected msg_style: %d\n", m->msg_style);
break;
}
}
return PAM_SUCCESS;
}
int main(void)
{
struct pam_conv pam_conv = {conversation, NULL};
pam_handle_t *pamh;
/* echo on while exist, like Ctrl+C on input password */
atexit(echoOnStdin);
if (PAM_SUCCESS != pam_start("login", NULL, &pam_conv, &pamh))
{
fprintf(stderr, "pam_start failed\n");
return EXIT_FAILURE;
}
if (PAM_SUCCESS != pam_authenticate(pamh, 0))
{
fprintf(stderr, "pam_authenticate failed\n");
pam_end(pamh, 0);
return EXIT_FAILURE;
}
if (PAM_SUCCESS != pam_acct_mgmt(pamh, 0))
{
fprintf(stderr, "pam_acct_mgmt failed\n");
pam_end(pamh, 0);
return EXIT_FAILURE;
}
pam_end(pamh, 0);
return EXIT_SUCCESS;
}
|