// ----------------------------------------------------------
// File:	ni_krb5.c
//
// Contents:	main module for ni_krb5.dll.
//				ni_krb5.dll is the DLL to provide  
//				authentication module which authenticates on kerberos-5,
//				for ni_pam 
// 
// History:		7-2-97	Naomaru Itoi	created
//				7-14-1997	modified to support logout, change password

#include "ni_krb5.h"
// global valuables. 
HINSTANCE	hDllInstance;	// my instance
CHAR username[256], password[256];

// functions

BOOL
WINAPI
DllMain(
		HINSTANCE hInstance,
		DWORD dwReason,
		LPVOID lpReserved)
{
    switch (dwReason)
    {
        case DLL_PROCESS_ATTACH:
            DisableThreadLibraryCalls ( hInstance );
            hDllInstance = hInstance;

        case DLL_PROCESS_DETACH:
        default:
            return(TRUE);
    }
}

BOOL
WINAPI
ni_sm_authenticate(NISTRUCT *niStruct)
{	
	krb5_error_code code;
	krb5_context context;
	krb5_ccache ccache;
	krb5_principal server, me;//, *me_p;
	krb5_creds my_creds;
	krb5_timestamp now;
	krb5_deltat lifetime = KRB5_DEFAULT_LIFE;
	//krb5_creds tgt_creds;
	
	WCHAR wcBuf[256];
	

	krb5_data tgtname = {
		0,
		KRB5_TGS_NAME_SIZE,
		KRB5_TGS_NAME
	};	

	wprintf(L"%d: ni_krb5 start\n", GetTickCount());

	WideCharToMultiByte(CP_ACP,0,niStruct->username,-1,username,
						256,(LPCSTR)0,(LPBOOL)0);
	WideCharToMultiByte(CP_ACP,0,niStruct->password,-1,password,
						256,(LPCSTR)0,(LPBOOL)0);


	D(L"ni_krb5 : ni_sm_authenticate() called. \n");
	// We don't allow null Kerberos password
	if (!password) return NI_FAILURE;
	// initialize krb5 context
	if (code = krb5_init_context(&context)) {
		NIError(L"Initializing krb5 context", L"NI_KRB5");
		return NI_FAILURE;
	}
	DS(L"code(init_context)=%d\n", code);
	// get credential cache
	if (code = krb5_cc_default(context, &ccache)) {
	NIError(L"getting credential cache", L"NI_KRB5");
		return NI_FAILURE;
	}
	// setup credentials 
    memset((CHAR *)&my_creds, 0, sizeof(my_creds));
  
    // parse from name
     code = krb5_parse_name (context, username, &me);
     if (code) {
       NIError(L"parsing name",L"NI_KRB5");
	   krb5_cc_destroy (context, ccache);
       return NI_FAILURE;
     }
     my_creds.client = me;
     // initialize cc 
     code = krb5_cc_initialize (context, ccache, me);
     if (code) {
		 krb5_cc_destroy (context, ccache);
		 NIError(L"cannot initialize context", L"NI_KRB5");
       return NI_FAILURE;
     }
     
	 // build server name
     code = krb5_build_principal_ext(context, &server,
				     krb5_princ_realm(context, me)->length,
				     krb5_princ_realm(context, me)->data,
				     tgtname.length, tgtname.data,
				     krb5_princ_realm(context, me)->length,
				     krb5_princ_realm(context, me)->data,
				     0);
     if (code) {
       NIError(L"cannot build server name",L"NI_KRB5");
       {
		krb5_cc_destroy (context, ccache);
		return NI_FAILURE;
       }
     }
    
     my_creds.server = server;
  
     code = krb5_timeofday(context, &now);
     if (code) {
       NIError(L"_cannot get time of day", L"NI_KRB5");
       krb5_cc_destroy (context, ccache);
       return NI_FAILURE;
	 }
     my_creds.times.starttime = 0; // start timer when request gets to KDC
     my_creds.times.endtime = now + lifetime;
     my_creds.times.renew_till = 0;
     
     // okay, now get tgt 
     code = krb5_get_in_tkt_with_password(context, 0,
					  0, NULL, 0,
					  password,
					  ccache,
					  &my_creds, 0);

	 DS(L"krb5_get_in_tkt_with_password() returns %ld\n", (unsigned int)code);
     
	if (code) {
		if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY){
		wsprintf (wcBuf,L"%s: %s\n", niStruct->username, MISTYPED_PASS);
		//NIError(wcBuf, L"NI_KRB5");
		MessageBox(NULL, wcBuf, L"NI_KRB5", (MB_OK | MB_SETFOREGROUND));
		}
		else {
			//NIError (L"problem getting tgt", L"NI_KRB5");
			MessageBox(NULL, L"problem getting tgt", L"NI_KRB5", (MB_OK | MB_SETFOREGROUND));
		}
		krb5_cc_destroy (context, ccache);
		return NI_FAILURE;
    }

     // verify the tgt 
	/*
     code = verify_krb_v5_tgt(context);
    if (code==-1){
      com_err ("_krb5_verify_password", code, "while verifying tgt");
      krb5_cc_destroy (context, ccache);
      return PAM_AUTH_ERR;
    }
*/ 
	wprintf(L"%d: ni_krb5 done\n", GetTickCount());

	wsprintf (wcBuf,L"%s: succeeded to get kerberos5 tgt\n", niStruct->username);
	NIError(wcBuf, L"NI_KRB5");
	return (NI_SUCCESS);
}


// ni_sm_logout()
// logout kerberos 5 = destroy k5 ticket.
// 1997/7/13, Naomaru Itoi, created

BOOL WINAPI ni_sm_logout()
{
	krb5_error_code code;
	krb5_context context;
	krb5_ccache ccache;
	krb5_deltat lifetime = KRB5_DEFAULT_LIFE;
	
	WCHAR wcBuf[256];
	
	krb5_data tgtname = {
		0,
		KRB5_TGS_NAME_SIZE,
		KRB5_TGS_NAME
	};	

	D(L"ni_krb5 : ni_sm_logout() called. \n");
	// initialize krb5 context
	if (code = krb5_init_context(&context)) {
		NIError(L"Initializing krb5 context", L"NI_KRB5");
		return NI_FAILURE;
	}
	// get credential cache
	if (code = krb5_cc_default(context, &ccache)) {
	NIError(L"getting credential cache", L"NI_KRB5");
		return NI_FAILURE;
	}
	krb5_cc_destroy (context, ccache);
	return NI_SUCCESS;
}

// ni_sm_chpass_check()
// preliminary check for change password protocol.
// 7-14-1997, Naomaru Itoi, created

INT WINAPI ni_sm_chpass_check(NISTRUCT *niStruct)
{
	return NI_SUCCESS;
}

// ni_sm_chpass()
// change password function.
// 7-14-1997, Naomaru Itoi, created

INT WINAPI ni_sm_chpass(NISTRUCT *niStruct)
{
	return NI_SUCCESS;
}
