/*
 * pam_krb5_auth.c
 *
 * PAM authentication management functions for pam_krb5
 *
 */

static const char rcsid[] = "$Id: pam_krb5_auth.c,v 1.8 2002/08/04 21:58:49 hartmans Exp $";

#include <errno.h>
#include <limits.h>	/* PATH_MAX */
#include <pwd.h>	/* getpwnam */
#include <stdio.h>	/* tmpnam */
#include <stdlib.h>	/* malloc  */
#include <string.h>	/* strchr */
#include <syslog.h>	/* syslog */
#include <unistd.h>	/* chown */
#include <sys/types.h>	/* chown */
#include <sys/wait.h>   /* waitpid */ // added by tabbott

#include <security/pam_appl.h>
#include <security/pam_modules.h>

#include <krb5.h>
#include <com_err.h>
#include "pam_krb5.h"

#define MAXBUF 256  // add by tabbott 

void Jokostat(char *);
extern krb5_cc_ops krb5_mcc_ops;

/* A useful logging macro */
#define DLOG(error_func, error_msg) \
if (debug) \
    syslog(LOG_DEBUG, "pam_krb5: pam_sm_authenticate(%s %s): %s: %s", \
	   service, name, error_func, error_msg)

/* Authenticate a user via krb5 */
int
pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
		    const char **argv)
{
    krb5_error_code	krbret;
    krb5_context	pam_context;
    krb5_creds		creds;
    krb5_principal	princ;
    krb5_ccache		ccache, ccache_check;
    krb5_get_init_creds_opt opts;

    int			pamret, i;
    const char		*name;
    char		*princ_name = NULL;
    char		*pass = NULL, *service = NULL;
    char		*prompt = NULL;
    char		cache_name[L_tmpnam + 8];
    char		lname[64]; /* local acct name */

    int debug = 0, try_first_pass = 0, use_first_pass = 0;
    int forwardable = 0, reuse_ccache = 0, no_ccache = 0;

    for (i = 0; i < argc; i++) {
	if (strcmp(argv[i], "debug") == 0)
	    debug = 1;
	else if (strcmp(argv[i], "try_first_pass") == 0)
	    try_first_pass = 1;
	else if (strcmp(argv[i], "use_first_pass") == 0)
	    use_first_pass = 1;
	else if (strcmp(argv[i], "forwardable") == 0)
	    forwardable = 1;
	else if (strcmp(argv[i], "reuse_ccache") == 0)
	    reuse_ccache = 1;
	else if (strcmp(argv[i], "no_ccache") == 0)
	    no_ccache = 1;
    }

    /* Get username */
    if ((pamret = pam_get_user(pamh, &name, "login: ")) != PAM_SUCCESS) {
	return PAM_SERVICE_ERR;
    }

    /* Get service name */
    (void) pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
    if (!service)
	service = "unknown";

    DLOG("entry", "");

    if ((krbret = krb5_init_context(&pam_context)) != 0) {
	DLOG("krb5_init_context()", error_message(krbret));
	return PAM_SERVICE_ERR;
    }
    krb5_get_init_creds_opt_init(&opts);
    memset(&creds, 0, sizeof(krb5_creds));
    memset(cache_name, 0, sizeof(cache_name));
    memset(lname, 0, sizeof(lname));

    if (forwardable)
	krb5_get_init_creds_opt_set_forwardable(&opts, 1);

    /* For CNS */
    if ((krbret = krb5_cc_register(pam_context, &krb5_mcc_ops, FALSE)) != 0) {
	/* Solaris dtlogin doesn't call pam_end() on failure */
	if (krbret != KRB5_CC_TYPE_EXISTS) {
	    DLOG("krb5_cc_register()", error_message(krbret));
	    pamret = PAM_SERVICE_ERR;
	    goto cleanup3;
	}
    }

    /* Get principal name */
    if ((krbret = krb5_parse_name(pam_context, name, &princ)) != 0) {
	DLOG("krb5_parse_name()", error_message(krbret));
	pamret = PAM_SERVICE_ERR;
	goto cleanup3;
    }

    /* Now convert the principal name into something human readable */
    if ((krbret = krb5_unparse_name(pam_context, princ, &princ_name)) != 0) {
	DLOG("krb5_unparse_name()", error_message(krbret));
	pamret = PAM_SERVICE_ERR;
	goto cleanup2;
    }

    /* Get password */
    prompt = malloc(16 + strlen(princ_name));
    if (!prompt) {
	DLOG("malloc()", "failure");
	pamret = PAM_BUF_ERR;
	goto cleanup2;
    }
    (void) sprintf(prompt, "Password for %s: ", princ_name);

    if (try_first_pass || use_first_pass)
	(void) pam_get_item(pamh, PAM_AUTHTOK, (const void **) &pass);

get_pass:
    if (!pass) {
	try_first_pass = 0;
	if ((pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF,
	  &pass)) != 0) {
	    DLOG("get_user_info()", pam_strerror(pamh, pamret));
	    pamret = PAM_SERVICE_ERR;
	    goto cleanup2;
	}
	/* We have to free pass. */
	if ((pamret = pam_set_item(pamh, PAM_AUTHTOK, pass)) != 0) {
	    DLOG("pam_set_item()", pam_strerror(pamh, pamret));
	    free(pass);
	    pamret = PAM_SERVICE_ERR;
	    goto cleanup2;
	}
	free(pass);
	/* Now we get it back from the library. */
	(void) pam_get_item(pamh, PAM_AUTHTOK, (const void **) &pass);
    }

    /* Verify the local user exists (AFTER getting the password) */
    if (strchr(name, '@')) {
	/* get a local account name for this principal */
	if ((krbret = krb5_aname_to_localname(pam_context, princ, 
	  sizeof(lname), lname)) != 0) {
	    DLOG("krb5_aname_to_localname()", error_message(krbret));
	    pamret = PAM_USER_UNKNOWN;
	    goto cleanup2;
	}
	DLOG("changing PAM_USER to", lname);
	if ((pamret = pam_set_item(pamh, PAM_USER, lname)) != 0) {
	    DLOG("pam_set_item()", pam_strerror(pamh, pamret));
	    pamret = PAM_SERVICE_ERR;
	    goto cleanup2;
	}
	if ((pamret = pam_get_item(pamh, PAM_USER, (const void **) &name)
	  != 0)) {
	    DLOG("pam_get_item()", pam_strerror(pamh, pamret));
	    pamret = PAM_SERVICE_ERR;
	    goto cleanup2;
	}
    }
    /* Get a TGT */
    if ((krbret = krb5_get_init_creds_password(pam_context, &creds, princ,
      pass, pam_prompter, pamh, 0, NULL, &opts)) != 0) {
	DLOG("krb5_get_init_creds_password()", error_message(krbret));
	if (try_first_pass && krbret == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
	    pass = NULL;
	    goto get_pass;
	}
        if (krbret == KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN)
            pamret = PAM_USER_UNKNOWN;
        else if (krbret == KRB5_KDC_UNREACH)
            pamret = PAM_AUTHINFO_UNAVAIL;
        else
            pamret = PAM_AUTH_ERR;
	goto cleanup2;
    }

    /* Generate a unique cache_name */
    strcpy(cache_name, "MEMORY:");
    (void) tmpnam(&cache_name[7]);

    if ((krbret = krb5_cc_resolve(pam_context, cache_name, &ccache)) != 0) {
	DLOG("krb5_cc_resolve()", error_message(krbret));
	pamret = PAM_SERVICE_ERR;
	goto cleanup;
    }
    if ((krbret = krb5_cc_initialize(pam_context, ccache, princ)) != 0) {
	DLOG("krb5_cc_initialize()", error_message(krbret));
	pamret = PAM_SERVICE_ERR;
 	goto cleanup;
    }
    if ((krbret = krb5_cc_store_cred(pam_context, ccache, &creds)) != 0) {
	DLOG("krb5_cc_store_cred()", error_message(krbret));
	(void) krb5_cc_destroy(pam_context, ccache);
	pamret = PAM_SERVICE_ERR;
	goto cleanup;
    }

    /* Verify it */
    if (verify_krb_v5_tgt(pam_context, ccache, service, debug) == -1) {
	(void) krb5_cc_destroy(pam_context, ccache);
	pamret = PAM_AUTH_ERR;
	goto cleanup;
    }

    /* A successful authentication, store ccache for sm_setcred() */
    if (!pam_get_data(pamh, "ccache", (const void **) &ccache_check)) {
	DLOG("pam_get_data()", "ccache data already present");
	(void) krb5_cc_destroy(pam_context, ccache);
	pamret = PAM_AUTH_ERR;
	goto cleanup;
    }
    if ((pamret = pam_set_data(pamh, "ccache", ccache, cleanup_cache)) != 0) {
	DLOG("pam_set_data()", pam_strerror(pamh, pamret));
	(void) krb5_cc_destroy(pam_context, ccache);
	pamret = PAM_SERVICE_ERR;
	goto cleanup;
    }


cleanup:
    krb5_free_cred_contents(pam_context, &creds);
cleanup2:
    krb5_free_principal(pam_context, princ);
cleanup3:
    if (prompt)
	free(prompt);
    if (princ_name)
	free(princ_name);

    krb5_free_context(pam_context);
    DLOG("exit", pamret ? "failure" : "success");
    return pamret;
}



/* redefine this for pam_sm_setcred() */
#undef DLOG
#define DLOG(error_func, error_msg) \
if (debug) \
    syslog(LOG_DEBUG, "pam_krb5: pam_sm_setcred(%s %s): %s: %s", \
	   service, name, error_func, error_msg)

/* Called after a successful authentication. Set user credentials. */
int
pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,
	       const char **argv)
{

    krb5_error_code	krbret;
    krb5_context	pam_context;
    krb5_principal	princ;
    krb5_creds		creds;
    krb5_ccache		ccache_temp, ccache_perm, ccache_check;
    krb5_cc_cursor	cursor;

    int			i, pamret;
    char		*name, *service = NULL;
    char		*cache_name = NULL, *cache_env_name;
    struct passwd	*pw = NULL;

    int status;  // added by tabbott

    int		debug = 0;
    uid_t	euid;
    gid_t	egid;

    /* XXX The meaning of PAM_REINITIALIZE_CRED is unclear, but ssh calls
       this function without it and then with it as part of a normal login.
       The right thing may be to fall through and do what we would normally
       do with PAM_ESTABLISH_CRED, but the below works in practice. */
    if ((flags | PAM_SILENT) == (PAM_REINITIALIZE_CRED | PAM_SILENT))
	return PAM_SUCCESS;

    if ((flags | PAM_SILENT) != (PAM_ESTABLISH_CRED | PAM_SILENT) )
	return PAM_SERVICE_ERR;

    for (i = 0; i < argc; i++) {
	if (strcmp(argv[i], "debug") == 0)
	    debug = 1;
	else if (strcmp(argv[i], "no_ccache") == 0)
	    return PAM_SUCCESS;
	else if (strstr(argv[i], "ccache=") == argv[i])
	    cache_name = (char *) &argv[i][7]; /* save for later */
    }

    /* Get username */
    if (pam_get_item(pamh, PAM_USER, (const void **) &name)) {
	return PAM_SERVICE_ERR;
    }

    /* Get service name */
    (void) pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
    if (!service)
	service = "unknown";

    DLOG("entry", "");

    if ((krbret = krb5_init_context(&pam_context)) != 0) {
	DLOG("krb5_init_context()", error_message(krbret));
	return PAM_SERVICE_ERR;
    }
    if (pam_get_data (pamh, "ccache_perm", (const void **) &ccache_perm) == 0 ) {
      DLOG ("pam_get_data", "ALready set up credentials");
	return PAM_SUCCESS;
    }
    euid = geteuid(); /* Usually 0 */
    egid = getegid();

    /* Get the uid. This should exist. */
    pw = getpwnam(name);
    if (!pw) {
	DLOG("getpwnam()", name);
	pamret = PAM_USER_UNKNOWN;
	goto cleanup3;
    }

    /* Avoid following a symlink as root */
    if (setegid(pw->pw_gid)) {
	DLOG("setegid()", name);
	pamret = PAM_SERVICE_ERR;
	goto cleanup3;
    }
    if (seteuid(pw->pw_uid)) {
	DLOG("seteuid()", name);
	pamret = PAM_SERVICE_ERR;
	goto cleanup3;
    }

    // tabbott start

    char * forward_cache_name;
    forward_cache_name = pam_getenv(pamh,"KRB5CCNAME");
    //    DLOG("PAMDATA:", forward_cache_name);
    if (forward_cache_name) {
      DLOG("Ticket Forwarded", forward_cache_name);
      cache_name = forward_cache_name;
      char *cache_name4 = NULL, *cache_env_name4;
      /* Create the krb4 cache name */
      if (!cache_name4) {
        int ccache_fd4;
        size_t ccache_size4 = strlen("/tmp/tkt_4294967295_XXXXXX") + 1;
        cache_name4 = malloc(ccache_size4);
	if (!cache_name4) {
	  DLOG("malloc()", "failure");
	  pamret = PAM_BUF_ERR;
	  goto cleanup3;
	}
        snprintf(cache_name4, ccache_size4, "/tmp/tkt_%d_XXXXXX",
                 pw->pw_uid);
	ccache_fd4 = mkstemp(cache_name4);
	if (ccache_fd4 == -1) {
	  DLOG ("mkstemp()", "failure");
	  pamret = PAM_BUF_ERR;
	  goto cleanup3;
	}

	//	char buf3[100];
	//	sprintf(buf3, "%d %d %d %d", getuid(), geteuid(), getgid(), getegid());
	//	DLOG("UID", buf3);
	
	// change ownership of mkstemp-created file so that
	// krb524init doesn't get confused.
	fchown(ccache_fd4, getuid(), getgid());
	//	DLOG("Changed Mode", "moo");
	close(ccache_fd4);
	
      }
      DLOG("Got KRB4 Name:", cache_name4);
      cache_env_name4 = malloc(strlen(cache_name4) + 12);
      if (!cache_env_name4) {
	DLOG("malloc()", "failure");
	(void) krb5_cc_destroy(pam_context, ccache_perm);
	pamret = PAM_BUF_ERR;
	goto cleanup2;
      }

      sprintf(cache_env_name4, "KRBTKFILE=%s", cache_name4);
      if ((pamret = pam_putenv(pamh, cache_env_name4)) != 0) {
	DLOG("pam_putenv()", pam_strerror(pamh, pamret));
	(void) krb5_cc_destroy(pam_context, ccache_perm);
	pamret = PAM_SERVICE_ERR;
	goto cleanup2;
      }
      int pid;
      pid=fork();
      if(pid==0) {
      //      DLOG("Moo:", pw->pw_uid);
      //      if(setuid(pw->pw_uid) < 0) {
      //	DLOG("setuid","Unable to set the appropriate UID");
      //	exit(1);
      // }
      //      snprintf(buf2,MAXBUF-1,"%s=%s","KRBTKFILE",);

	// setup the environoment
	char * envi[3];
	envi[2] = NULL;
	char buf[MAXBUF];    
	snprintf(buf,MAXBUF-1,"%s=%s","KRB5CCNAME",cache_name);
	envi[0]=buf;
	char buf2[MAXBUF];    
	snprintf(buf2,MAXBUF-1,"%s=%s","KRBTKFILE",cache_name4);
	envi[1]=buf2;
	//	DLOG("ENVIRONNEMENT", envi[0]);
	//	DLOG("ENVIRONNEMENT", envi[1]);
	//      DLOG("UID", geteuid());
	
	// make the forked process have the right real UID for krb524init
	// which is very unhappy with uid!=euid.
	setregid(getegid(), getegid());
	setreuid(geteuid(), geteuid());
	//	char buf3[100];
	//	sprintf(buf3, "%d %d %d %d", getuid(), geteuid(), getgid(), getegid());
	//	DLOG("UID", buf3);
	
	execle("/usr/bin/krb524init","krb524init",NULL,envi);       
	DLOG("open_session","fatal error");
	exit(-1);
      }
      waitpid(pid, &status, 0);
      //      DLOG("Done", "moo");
      if(!WIFEXITED(status)) {
	DLOG("krb524init", "NOT OK !");
      }
      // done with krb524, end.  
      pamret = PAM_SUCCESS;
      goto cleanup3;
    }
    
    // tabbott end 

    /* Retrieve the cache name */
    if ((pamret = pam_get_data(pamh, "ccache", (const void **) &ccache_temp)) 
      != 0) {
	DLOG("pam_get_data()", pam_strerror(pamh, pamret));
	pamret = PAM_CRED_UNAVAIL;
	goto cleanup3;
    }

    /* Get the cache name */
    if (!cache_name) {
        int ccache_fd;
        size_t ccache_size = strlen("/tmp/krb5cc_4294967295_XXXXXX") + 1;

        cache_name = malloc(ccache_size);
	if (!cache_name) {
	    DLOG("malloc()", "failure");
	    pamret = PAM_BUF_ERR;
	    goto cleanup3;
	}
        snprintf(cache_name, ccache_size, "/tmp/krb5cc_%d_XXXXXX",
                 pw->pw_uid);
	ccache_fd = mkstemp(cache_name);
	if (ccache_fd == -1) {
            DLOG ("mkstemp()", "failure");
	    pamret = PAM_BUF_ERR;
	    goto cleanup3;
	}
	close(ccache_fd);

    } else {
	/* cache_name was supplied */
	char *p = calloc(PATH_MAX + 10, 1); /* should be plenty */
	char *q = cache_name;
	if (!p) {
	    DLOG("malloc()", "failure");
	    pamret = PAM_BUF_ERR;
	    goto cleanup3;
	}
	cache_name = p;
	
	/* convert %u and %p */
	while (*q) {
	    if (*q == '%') {
		q++;
		if (*q == 'u') {
		    sprintf(p, "%d", pw->pw_uid);
		    p += strlen(p);
		} else if (*q == 'p') {
		    sprintf(p, "%d", getpid());
		    p += strlen(p);
		} else {
		    /* Not a special token */
		    *p++ = '%';
		    q--;
		}
		q++;
	    } else {
		*p++ = *q++;
	    }
	}
    }

    /* Initialize the new ccache */
    if ((krbret = krb5_cc_get_principal(pam_context, ccache_temp, &princ)) 
	!= 0) {
	DLOG("krb5_cc_get_principal()", error_message(krbret));
	pamret = PAM_SERVICE_ERR;
	goto cleanup3;
    }
    if ((krbret = krb5_cc_resolve(pam_context, cache_name, &ccache_perm)) 
      != 0) {
	DLOG("krb5_cc_resolve()", error_message(krbret));
	pamret = PAM_SERVICE_ERR;
	goto cleanup2;
    }
    if ((krbret = krb5_cc_initialize(pam_context, ccache_perm, princ)) != 0) {
	DLOG("krb5_cc_initialize()", error_message(krbret));
	pamret = PAM_SERVICE_ERR;
 	goto cleanup2;
    }

    /* Prepare for iteration over creds */
    if ((krbret = krb5_cc_start_seq_get(pam_context, ccache_temp, &cursor)) 
      != 0) {
	DLOG("krb5_cc_start_seq_get()", error_message(krbret));
	(void) krb5_cc_destroy(pam_context, ccache_perm);
	pamret = PAM_SERVICE_ERR;
	goto cleanup2;
    }

    /* Copy the creds (should be two of them) */
    while ((krbret = compat_cc_next_cred(pam_context, ccache_temp,
	&cursor, &creds) == 0)) {
	    if ((krbret = krb5_cc_store_cred(pam_context, ccache_perm, 
		&creds)) != 0) {
	    DLOG("krb5_cc_store_cred()", error_message(krbret));
	    (void) krb5_cc_destroy(pam_context, ccache_perm);
	    krb5_free_cred_contents(pam_context, &creds);
	    pamret = PAM_SERVICE_ERR;
	    goto cleanup2;
	}
	krb5_free_cred_contents(pam_context, &creds);
    }
    (void) krb5_cc_end_seq_get(pam_context, ccache_temp, &cursor);
    
    if (strstr(cache_name, "FILE:") == cache_name) {
	if (chown(&cache_name[5], pw->pw_uid, pw->pw_gid) == -1) {
	    DLOG("chown()", strerror(errno));
	    (void) krb5_cc_destroy(pam_context, ccache_perm);
	    pamret = PAM_SERVICE_ERR;	
	    goto cleanup2;
	}
    }


    cache_env_name = malloc(strlen(cache_name) + 12);
    if (!cache_env_name) {
	DLOG("malloc()", "failure");
	(void) krb5_cc_destroy(pam_context, ccache_perm);
	pamret = PAM_BUF_ERR;
	goto cleanup2;
    }

    sprintf(cache_env_name, "KRB5CCNAME=%s", cache_name);
    DLOG("KRB5 DONE", "YAY");
    if ((pamret = pam_putenv(pamh, cache_env_name)) != 0) {
	DLOG("pam_putenv()", pam_strerror(pamh, pamret));
	(void) krb5_cc_destroy(pam_context, ccache_perm);
	pamret = PAM_SERVICE_ERR;
	goto cleanup2;
    }
    if (!pam_get_data(pamh, "ccache_perm", (const void **) &ccache_check)) {
	DLOG("pam_get_data()", "permanent ccache data already present");
	(void) krb5_cc_destroy(pam_context, ccache_perm);
	pamret = PAM_SERVICE_ERR;
	goto cleanup2;
    }
    if ((pamret = pam_set_data(pamh, "ccache_perm", ccache_perm, cleanup_cache)) != 0) {
	DLOG("pam_set_data()", pam_strerror(pamh, pamret));
	(void) krb5_cc_destroy(pam_context, ccache_perm);
	pamret = PAM_SERVICE_ERR;
	goto cleanup2;
    }

    // tabbott start
    //    DLOG("KRB4 START", "YAY");
    char *cache_name4 = NULL, *cache_env_name4;
    /* Create the krb4 cache name */
    if (!cache_name4) {
        int ccache_fd4;
        size_t ccache_size4 = strlen("/tmp/tkt_4294967295_XXXXXX") + 1;

        cache_name4 = malloc(ccache_size4);
	if (!cache_name4) {
	    DLOG("malloc()", "failure");
	    pamret = PAM_BUF_ERR;
	    goto cleanup3;
	}
        snprintf(cache_name4, ccache_size4, "/tmp/tkt_%d_XXXXXX",
                 pw->pw_uid);
	ccache_fd4 = mkstemp(cache_name4);
	if (ccache_fd4 == -1) {
            DLOG ("mkstemp()", "failure");
	    pamret = PAM_BUF_ERR;
	    goto cleanup3;
	}

	//char buf3[100];
	//sprintf(buf3, "%d %d %d %d", getuid(), geteuid(), getgid(), getegid());
	//DLOG("UID", buf3);

	// change ownership of mkstemp-created file so that
	// krb524init doesn't get confused.
	fchown(ccache_fd4, getuid(), getgid());
	//	DLOG("Changed Mode", "moo");
	close(ccache_fd4);

    }
    DLOG("Got KRB4 Name:", cache_name4);
    cache_env_name4 = malloc(strlen(cache_name4) + 12);
    if (!cache_env_name4) {
	DLOG("malloc()", "failure");
	(void) krb5_cc_destroy(pam_context, ccache_perm);
	pamret = PAM_BUF_ERR;
	goto cleanup2;
    }
    sprintf(cache_env_name4, "KRBTKFILE=%s", cache_name4);
    if ((pamret = pam_putenv(pamh, cache_env_name4)) != 0) {
	DLOG("pam_putenv()", pam_strerror(pamh, pamret));
	(void) krb5_cc_destroy(pam_context, ccache_perm);
	pamret = PAM_SERVICE_ERR;
	goto cleanup2;
    }
    int pid;
    pid=fork();
    if(pid==0) {
      //      DLOG("Moo:", pw->pw_uid);
      //      if(setuid(pw->pw_uid) < 0) {
      //	DLOG("setuid","Unable to set the appropriate UID");
      //	exit(1);
      // }
      //      snprintf(buf2,MAXBUF-1,"%s=%s","KRBTKFILE",);
      char * envi[3];
      envi[2] = NULL;
      char buf[MAXBUF];    
      snprintf(buf,MAXBUF-1,"%s=%s","KRB5CCNAME",cache_name);
      envi[0]=buf;
      char buf2[MAXBUF];    
      snprintf(buf2,MAXBUF-1,"%s=%s","KRBTKFILE",cache_name4);
      envi[1]=buf2;
      //      DLOG("ENVIRONNEMENT", envi[0]);
      //      DLOG("ENVIRONNEMENT", envi[1]);
      //      DLOG("UID", geteuid());

      setregid(getegid(), getegid());
      setreuid(geteuid(), geteuid());
      //      char buf3[100];
      //      sprintf(buf3, "%d %d %d %d", getuid(), geteuid(), getgid(), getegid());
      //      DLOG("UID", buf3);
      execle("/usr/bin/krb524init","krb524init",NULL,envi);       
      DLOG("open_session","fatal error");
      exit(-1);
    }
    waitpid(pid, &status, 0);
    if(!WIFEXITED(status)) {
      DLOG("krb524init", "NOT OK !");
    }
    // tabbott end

cleanup2:
    krb5_free_principal(pam_context, princ);
cleanup3:
    krb5_free_context(pam_context);
    DLOG("exit", pamret ? "failure" : "success");
    (void) seteuid(euid);
    (void) setegid(egid);
    return pamret;
}

#include <sys/stat.h>
void Jokostat(char *n)
{
	struct stat	b;
	int		ret;

	if (strstr(n, "FILE:") != n) {
		syslog(LOG_DEBUG, "Jokostat: no fcache: %s", n);
		return;
	}

	ret=stat(&n[5],&b);
	if(ret!=0)
	{
		syslog(LOG_DEBUG, "Jokostat prout");
		return;
	}

	syslog(LOG_DEBUG, "Jokostat: %d %d:%d %o", geteuid(), b.st_uid, b.st_gid, b.st_mode);

	return;
}

