/*
 * T.C.F.S. Utils 2.0 $Revision: 2.2 $
 *
 * Authors:	Giuseppe Cattaneo, <cattaneo@udsab.dia.unisa.it>
 *		Giuseppe Persiano, <giuper@udsab.dia.unisa.it>
 *		Luigi Catuogno, <luicat@mikonos.dia.unisa.it>
 *		Angelo Celentano, <angcel@mikonos.dia.unisa.it>
 *		Andrea Cozzolino, <andcoz@mikonos.dia.unisa.it>
 *		Aniello Del Sorbo, <anidel@mikonos.dia.unisa.it>
 *		Ermelindo Mauriello, <ermmau@mikonos.dia.unisa.it>
 *		Raffaele Pisapia, <rafpis@mikonos.dia.unisa.it>
 *
 * Permission  to use,  copy,  and modify this  software  without fee
 * is hereby granted, provided that this entire notice is included in
 * all  copies  of  any  software  which  is  or includes  a copy  or
 * modification of this  software and in all copies of the supporting
 * documentation for such software.
 *
 * This  software maybe  be used for  any purpose provided  the above 
 * copyright  notice  is  retained.  It is  supplied as  is, with  no 
 * warranty expressed or implied.
 */

/*
 *       $Source: /home/anidel/Wip/TCFS-2.2.0a/tcfslib-0.2/src/RCS/pam_tcfs.c,v $
 *        $State: Exp $
 *
 *     $Revision: 2.2 $
 *       $Author: anidel $
 *         $Date: 1998/12/01 15:07:33 $
 *       $Locker:  $
 */

static const char *RCSid="$Id: pam_tcfs.c,v 2.2 1998/12/01 15:07:33 anidel Exp $";
/* -+-_== */ 

#define PAM_SM_AUTH
#define PAM_SM_SESSION
#define PAM_SM_PASSWORD
#include <security/pam_modules.h>
#include <syslog.h>

#include "tcfspwdb.h"
#include "tcfslib.h"

/* PAM--- authentication management functions --- */

PAM_EXTERN int
pam_sm_authenticate (pam_handle_t * pamh, int flags, int argc
		     ,const char **argv)
{
  int r, retval, dummy;
  char *p, *u;
  static char *tk;
  static struct tcfspwdb_r t;

  r = pam_get_item (pamh, PAM_USER, (const void**)&u);
  if (r != PAM_SUCCESS)
    {
      syslog (LOG_WARNING, "pam_tcfs got problems retrieving user name");
      return r;
    }

  r = pam_get_item (pamh, PAM_AUTHTOK, (const void**)&p);
  if (r != PAM_SUCCESS || (!p))
    {
      syslog (LOG_WARNING, "pam_tcfs got problems retrieving auth. token");
      return r;
    }


  if (!tcfs_getpwnam (u, &t))
    {
      syslog (LOG_INFO, "%s is not a tcfs user.", u);
      return PAM_AUTH_ERR;
    }

  tk = (char *) malloc (KEYSIZE);
  if (!tk)
    {
      syslog (LOG_WARNING, "malloc failed");
      exit (1);
    }

  tcfs_decrypt_key (u, p, t.upw, tk);

  retval = pam_set_data (pamh, "tcfskey", tk, 0);
  if (retval != PAM_SUCCESS)
    return PAM_ABORT;

  syslog (LOG_INFO, "%s sucessfully attached tcfs", u);
  return PAM_SUCCESS;

}

PAM_EXTERN int
pam_sm_setcred (pam_handle_t * pamh, int flags, int argc,
		const char **argv)
{
  return PAM_SUCCESS;
}

PAM_EXTERN int
pam_sm_chauthtok (pam_handle_t * pamh, int flags, int argc
		  ,const char **argv)
{
  char *p, *u, *o;
  int r;


  if (flags & PAM_PRELIM_CHECK)
/*
   for now...
 */
    return PAM_SUCCESS;


  r = pam_get_item (pamh, PAM_USER, (const void**)&u);
  if (r != PAM_SUCCESS || !u)
    return r;

  r = pam_get_item (pamh, PAM_AUTHTOK, (const void**)&p);
  if (r != PAM_SUCCESS || !p)
    return r;

/* BUGFIX
   no more "core dumps" when root changes user's passwords;
 */

  if (!getuid ())
    {
      syslog (LOG_WARNING, "WARNING! destructive password changing, skipping tcfspasswd update");
      return PAM_SUCCESS;
    }

  r = pam_get_item (pamh, PAM_OLDAUTHTOK, (const void**)&o);
  if (r != PAM_SUCCESS || !o)
    return r;

  if (!(*u) || !(*o) || !(*p) || !p )
    return PAM_AUTHTOK_ERR;

  if (tcfs_chgpassword (u, o, p))
    return PAM_SUCCESS;


  return PAM_AUTHTOK_ERR;
}

/* --- session management --- */

PAM_EXTERN int
pam_sm_open_session (pam_handle_t * pamh, int flags, int argc
		     ,const char **argv)
{
  char *p, *u;
  static *pw, *un;
  int retval;

  retval = pam_get_item (pamh, PAM_USER, (void *) &u);
  if (retval != PAM_SUCCESS || (!u))
    {
      return retval;
    }


  retval = pam_get_data (pamh, "tcfskey", (void *) &p);
  if (retval != PAM_SUCCESS)
    return retval;

  if (!p)
    {
      syslog (LOG_WARNING, "pam_tcfs got problems retrieving auth. token");
      return PAM_SESSION_ERR;
    }


  retval = tcfs_enable (u, p);
  if (retval)
    {
      syslog (LOG_INFO, "starting tcfs session user %s", u);
      return PAM_SUCCESS;
    }
  return PAM_SESSION_ERR;
}

PAM_EXTERN int
pam_sm_close_session (pam_handle_t * pamh, int flags, int argc
		      ,const char **argv)
{
  char *user_name, *k;
  int retval;

  retval = pam_get_data (pamh, "tcfskey", (const void**)&k);
  if (retval != PAM_SUCCESS)
    return retval;

  retval = pam_get_item (pamh, PAM_USER, (void *) &user_name);
  if (retval != PAM_SUCCESS)
    return retval;

  retval = tcfs_disable (user_name, ONE);
  if (retval)
    {
      syslog (LOG_INFO, "ending tcfs session user %s", user_name);
      return PAM_SUCCESS;
    }

  return PAM_SESSION_ERR;
}

/* end of module definition */

/* static module data */
#ifdef PAM_STATIC
struct pam_module _pam_tcfs_modstruct =
{
  "pam_tcfs",
  pam_sm_authenticate,
  NULL,
  NULL,
  pam_sm_open_session,
  pam_sm_close_session,
  pam_sm_chauthtok
};
#endif
