/*
**  Copyright 2000-2003 University of Illinois Board of Trustees
**  Copyright 2000-2003 Mark D. Roth
**  All rights reserved. 
**
**  authtest.c - PAM authentication test program
**
**  Mark D. Roth <roth@uiuc.edu>
**  Campus Information Technologies and Educational Services
**  University of Illinois at Urbana-Champaign
*/


#include <stdio.h>
#include <unistd.h>
#include <security/pam_appl.h>
# include <string.h>
# include <stdlib.h>


#define BUFSIZE 1024


static int
PAM_conv(num_msg, msg, resp, appdata_ptr)
	int num_msg;
	const struct pam_message **msg;
	struct pam_response **resp;
	void *appdata_ptr;
{
	int replies = 0;
	struct pam_response *reply = NULL;
	char buf[BUFSIZE];
	char *pass;

#ifdef DEBUG
	printf("==> PAM_conv(num_msg=%d, msg=0x%lx, resp=0x%lx, "
	       "appdata_ptr=0x%lx)\n", num_msg, msg, resp, appdata_ptr);
#endif

	reply = malloc(sizeof(struct pam_response) * num_msg);
	if (reply == NULL)
		return PAM_CONV_ERR;

	for (replies = 0; replies < num_msg; replies++)
	{
		switch (msg[replies]->msg_style)
		{
		case PAM_PROMPT_ECHO_ON:
#ifdef DEBUG
			puts("PAM_PROMPT_ECHO_ON");
#endif
			reply[replies].resp_retcode = 0;
			printf("%s", msg[replies]->msg);
			fgets(buf, BUFSIZE, stdin);
			if (buf[strlen(buf) - 1] == '\n')
				buf[strlen(buf) - 1] = '\0';
			reply[replies].resp = strdup(buf);
			/* PAM frees resp */
			break;
		case PAM_PROMPT_ECHO_OFF:
#ifdef DEBUG
			puts("PAM_PROMPT_ECHO_OFF");
#endif
			reply[replies].resp_retcode = 0;
			pass = getpass(msg[replies]->msg);
			reply[replies].resp = strdup(pass);
			/* PAM frees resp */
			break;
		case PAM_TEXT_INFO:
#ifdef DEBUG
			puts("PAM_TEXT_INFO");
#endif
			/* fall through */
		case PAM_ERROR_MSG:
#ifdef DEBUG
			puts("PAM_ERROR_MSG");
#endif
			/* ignore it... */
			reply[replies].resp_retcode = 0;
			reply[replies].resp = NULL;
			break;
		default:
#ifdef DEBUG
			puts("(unknown msg_style)");
#endif
			/* Must be an error of some sort... */
			free(reply);
			return PAM_CONV_ERR;
		}
	}

	*resp = reply;

	return PAM_SUCCESS;
}


static struct pam_conv conv = {
	PAM_conv,
	NULL
};


int
main(int argc, char *argv[])
{
	pam_handle_t *pamh = NULL;
	int retval;
	const char *user = NULL;

	if (argc == 2)
		user = argv[1];

	if (argc > 2)
	{
		fprintf(stderr, "Usage: authtest [username]\n");
		exit(1);
	}

	retval = pam_start("authtest", user, &conv, &pamh);
#ifdef DEBUG
	fprintf(stderr, "pam_start(): %s\n", pam_strerror(pamh, retval));
#endif

	if (retval == PAM_SUCCESS)
		retval = pam_authenticate(pamh, 0);	/* is user really user? */

#if 0
	if (retval == PAM_SUCCESS)
		retval = pam_acct_mgmt(pamh, 0);	/* permitted access? */
#endif

	/* This is where we have been authorized or not. */

	if (retval == PAM_SUCCESS)
		fprintf(stdout, "Authenticated\n");
	else
		fprintf(stdout, "Not Authenticated\n");

	if (pam_end(pamh, retval) != PAM_SUCCESS)
	{			/* close Linux-PAM */
		pamh = NULL;
		fprintf(stderr,
			"check_user: failed to release authenticator\n");
		exit(1);
	}

	return (retval == PAM_SUCCESS ? 0 : 1);	/* indicate success */
}

