blob: 7cc5e3a392d168bb313905cfe760a3d88ede876c [file] [log] [blame]
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef HAVE_PAM_PAM_APPL_H
# include <pam/pam_appl.h>
#else
# include <security/pam_appl.h>
#endif
#ifdef LINUX_PAM /* XXX: and OpenPAM? */
# define PAM_MSG_MEMBER(msg, n, member) ((msg)[(n)]->member)
#else
# define PAM_MSG_MEMBER(msg, n, member) ((*(msg))[(n)].member)
#endif
int
my_conv(int n, const struct pam_message **msg,
struct pam_response **resp, void *data)
{
struct pam_response *aresp;
char buf[PAM_MAX_RESP_SIZE];
const char *p;
int i;
if (n <= 0 || n > PAM_MAX_NUM_MSG)
return (PAM_CONV_ERR);
if ((aresp = calloc(n, sizeof *aresp)) == NULL)
return (PAM_BUF_ERR);
for (i = 0; i < n; ++i) {
aresp[i].resp_retcode = 0;
aresp[i].resp = NULL;
p = PAM_MSG_MEMBER(msg, i, msg);
switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
case PAM_PROMPT_ECHO_OFF:
aresp[i].resp = strdup(getpass(p));
if (aresp[i].resp == NULL)
goto fail;
break;
case PAM_PROMPT_ECHO_ON:
fputs(p, stderr);
if (fgets(buf, sizeof(buf), stdin) == NULL)
goto fail;
aresp[i].resp = strdup(buf);
if (aresp[i].resp == NULL)
goto fail;
break;
case PAM_ERROR_MSG:
fputs(p, stderr);
if (strlen(p) > 0 && p[strlen(p) - 1] != '\n')
fputc('\n', stderr);
break;
case PAM_TEXT_INFO:
fputs(p, stdout);
if (strlen(p) > 0 && p[strlen(p) - 1] != '\n')
fputc('\n', stdout);
break;
default:
goto fail;
}
}
*resp = aresp;
return (PAM_SUCCESS);
fail:
for (i = 0; i < n; ++i) {
if (aresp[i].resp != NULL)
free(aresp[i].resp);
}
*resp = NULL;
return (PAM_CONV_ERR);
}
static struct pam_conv conv = { my_conv, NULL };
static void
die(pam_handle_t *pamh, int errnum)
{
//fprintf(stderr, "%s\n", pam_strerror(pamh, errnum));
exit(EXIT_FAILURE);
}
int
main(int argc, char *argv[])
{
pam_handle_t *pamh = NULL;
char *user, *host = NULL;
int ret;
if (argc < 2) {
fprintf(stderr, "Usage: testpam <user> [host]\n");
exit(EXIT_FAILURE);
}
user = argv[1];
if (argc > 2)
host = argv[2];
if ((ret = pam_start("testpam", user, &conv, &pamh)) != PAM_SUCCESS) {
die(pamh, ret);
}
if (host != NULL) {
if ((ret = pam_set_item(pamh, PAM_RHOST, host)) != PAM_SUCCESS)
die(pamh, ret);
}
if ((ret = pam_authenticate(pamh, 0)) != PAM_SUCCESS) {
die(pamh, ret);
}
if ((ret = pam_end(pamh, ret)) != PAM_SUCCESS) {
die(pamh, ret);
}
exit(EXIT_SUCCESS);
}