/*
Link options needed are:

int pam_check(char *user, char *pass, char *pam_type, char *host, 
  , char *extra, char *etext);

You must add a file called 'dmail' to /etc/pam.d/ containing
these lines, this file name matches the third parameter pam_type
above, it should be 'dmail' or dnews' 
  
auth       required     /lib/security/pam_pwdb.so shadow nullok
account    required     /lib/security/pam_pwdb.so

*/
#ifdef HAS_PAM
#include <security/pam_appl.h>
/* not needed on solaris anyway, probably not needed on linux 
#include <security/pam_misc.h>
*/
#include <stdio.h>
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif

int pam_my_conv(int msg, const struct pam_message **msgx, struct pam_response **resp, void *appdata_ptr);

static struct pam_conv conv = {
         pam_my_conv,
         NULL
};


/*#define TESTING 1*/
#ifdef TESTING     
int main(int argc, char *argv[])
{
	int r;
	char extra[1000];
	char etext[1000];
	if (argc<4) {
		printf("pamauth username password pam_type (dnews)\n");
	}
	r = pam_lookup(argv[1],argv[2],argv[3],"nohost", extra,etext);
	if (!r) {
		printf("Authentication failed (%s)\n",etext);
		return 0;
	}	
	printf("PAM authentication succeeded\n");
}
#endif TESTING

static char xpass[1000];
int pam_check(char *user, char *pass, char *pam_type, char *host, char *extra, char *etext)
{
	pam_handle_t *pamh=NULL;
	int r;
	int ret=FALSE;
	int flag=0;
	strcpy(etext,"No error");
	strcpy(xpass,pass);
	strcpy(extra,"");
#ifdef TESTING
	printf("Lookup user (%s) pass (%s) module (%s)\n",user,pass,pam_type);
#endif
        r = pam_start(pam_type, user, &conv, &pamh);
	             
        if (r != PAM_SUCCESS) {
		sprintf(etext,"pam_start failed %s\n",pam_strerror(pamh,r));
		return FALSE;
	}

#ifdef HAVE_PAM_FAIL_DELAY
	pam_fail_delay(pamh,10); /* cut out stupid delay if possible */
#endif /* HAVE_PAM_FAIL_DELAY */
       
	ret = FALSE;

	r = pam_set_item(pamh,PAM_RHOST,host);          /* host should contain the client hostname */ 
	if (!r) {
		dmsg("pam: pam_set_item error %s\n",pam_strerror(pamh,r));
	}

	flag = PAM_DISALLOW_NULL_AUTHTOK;
	r = pam_authenticate(pamh, flag);
	if (!r) {
		sprintf(etext,"pam_authenticate failed %s",pam_strerror(pamh,r));
	}
	if (r == PAM_SUCCESS) {
		r = pam_acct_mgmt(pamh, flag);  
		if (r==PAM_SUCCESS) {
			ret = TRUE;
			printf("Authenticated ok\n");
		} else 	sprintf(etext,"%s",pam_strerror(pamh,r));
/*		ret = TRUE; */
	}

        if (pam_end(pamh,r) != PAM_SUCCESS) {     /* close Linux-PAM */
		/*sprintf(etext,"pam_authenticate failed %s\n",pam_strerror(pamh,r));
		ret = FALSE;*/
        }
	return ret;
}

int pam_my_conv(int nmsg, const struct pam_message **msgx, struct pam_response **resp, void *appdata_ptr)
{
	int i;
	char bf[200];
	struct pam_response *reply;

	if (nmsg <= 0) return PAM_CONV_ERR;
	reply = calloc(nmsg,sizeof(struct pam_response));
	*resp = reply;

	for (i=0; i<nmsg; i++) {
#ifdef TESTING
		switch (msgx[i]->msg_style) {
			case PAM_PROMPT_ECHO_OFF:
				printf("Turn echo off (%s)\n",msgx[i]->msg);
				break;
			case PAM_PROMPT_ECHO_ON:
				printf("prompt echo (%s)\n",msgx[i]->msg);
				break;
			case PAM_ERROR_MSG:
				printf("error (%s)\n",msgx[i]->msg);
				break;
			case PAM_TEXT_INFO:
				printf("Info (%s)\n",msgx[i]->msg);
				break;
		}	
#endif
	reply[i].resp = strdup(xpass);
	reply[i].resp_retcode = 0;
	}
    return PAM_SUCCESS;

}
#endif