/*
 * Small tool to print the PAM prompts for a particular service when the
 * conversation function returns PAM_CONV_ERR.
 *
 * By Ted Percival <ted@midg3t.net>, 2008-06-18.
 *
 * Copyright © 2008, Quest Software
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Quest Software nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY QUEST SOFTWARE ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL QUEST SOFTWARE BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

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

static int conv(int num_msg, const struct pam_message **msg,
		struct pam_response **resp, void *appdata_ptr);

static void usage(const char *argv0, FILE *stream);

int main(int argc, char *argv[]) {
	char *service;
	char *username;
	pam_handle_t *pamh;
	int pam_status = PAM_SUCCESS;
	struct pam_conv pam_conv;

	if (argc < 3) {
		usage(argv[0], stderr);
		exit(1);
	}

	service = argv[1];
	username = argv[2];

	pam_conv.conv = conv;
	pam_conv.appdata_ptr = NULL;

	pam_status = pam_start(service, username, &pam_conv, &pamh);
	if (pam_status != PAM_SUCCESS)
		return 2;

	pam_status = pam_authenticate(pamh, 0);

	printf("PAM said %s\n", pam_strerror(pamh, pam_status));

	pam_end(pamh, pam_status);

	return 0;
}

void usage(const char *argv0, FILE *stream) {
	fprintf(stream, "Usage: %s <service> <username>\n", argv0);
}

int conv(int num_msg, const struct pam_message **msg,
		struct pam_response **resp, void *appdata_ptr) {
	int i;

	for (i = 0; i < num_msg; ++i) {
		printf("Message(%s): [%s]\n",
				msg[i]->msg_style == PAM_PROMPT_ECHO_OFF ? "PAM_PROMPT_ECHO_OFF" :
				msg[i]->msg_style == PAM_PROMPT_ECHO_ON ? "PAM_PROMPT_ECHO_ON" :
				msg[i]->msg_style == PAM_ERROR_MSG ? "PAM_ERROR_MSG" :
				msg[i]->msg_style == PAM_TEXT_INFO ? "PAM_TEXT_INFO" :
				"unknown",
				msg[i]->msg);
	}
	printf("(end of messages)\n\n");

	return PAM_CONV_ERR;
}

/* vim:ts=4:sw=4:noet
 */
