#include <security/pam_appl.h>
#include <windows.h>
#include <sys/cygwin.h>

int pam_start (const char * dummy, const char *user, const struct pam_conv * conv, pam_handle_t ** handle)
{
  int size;

  if (user && (size = strlen (user))
      && (*handle = (pam_handle_t *) malloc (sizeof (struct pam_handle) + size + 1)))
    {
      (*handle)->conv = conv->conv;
      (*handle)->appdata_ptr = conv->appdata_ptr;
      strcpy ((*handle)->name, user);
      return PAM_SUCCESS;
    }
  else
  {
    *handle = NULL;
    return PAM_AUTH_ERR;
  }
}

void pam_end(pam_handle_t * handle, int flag)
{
  if (handle)
    free (handle);
}

int pam_acct_mgmt (pam_handle_t * handle, int flag)
{
  if (handle)
    return PAM_SUCCESS;
  else
    return PAM_AUTH_ERR;
}

int pam_authenticate (pam_handle_t * handle, int flag)
{
  struct pam_response * resp;
  struct pam_message msg;
  const struct pam_message *msgs[1];
  struct passwd * pw;
  HANDLE cyghandle = NULL;
  int ret;

  if (!(handle && handle->name))
    return PAM_AUTH_ERR;
  if (!(pw = getpwnam (handle->name)))
    return PAM_USER_UNKNOWN;

  msg.msg_style = PAM_PROMPT_ECHO_OFF;
  msgs[0] = &msg;
  ret = PAM_CONV_ERR;
  if (handle->conv (1, msgs, &resp, handle->appdata_ptr) == PAM_SUCCESS)
    {
      if (resp[0].resp_retcode == PAM_SUCCESS
	  && resp[0].resp)
      {
	cyghandle = cygwin_logon_user (pw, resp[0].resp);
	free (resp[0].resp);
	if (cyghandle != INVALID_HANDLE_VALUE) {
	  CloseHandle (cyghandle);
	  ret = PAM_SUCCESS;
	}
	else
	  ret = PAM_AUTH_ERR;
      }
      free (resp);
    }
  return ret;
}

char * pam_strerror(pam_handle_t * pamh, unsigned int pam_error)
{
  static char * pam_err_list[PAM_MAX_ERR + 1] = {
    "Success",
    "User unknown",
    "Authentication error",
    "Conversation error",
    "Account expired",
    "Unknown error"
  };
  if (pam_error > PAM_MAX_ERR)
    pam_error = PAM_MAX_ERR;
  return pam_err_list[pam_error];
}
    
