#define SCALE_FACTOR 31/20

/* LSH_PWD.C

   Jason Hunter
   8/2/94
   DCNS/IS MIT


   Contains the callback functions for the EnterPassword an
   ChangePassword dialog boxes and well as the API function
   calls:

   Lsh_Enter_Password_Dialog
   Lsh_Change_Password_Dialog

   for calling the dialogs.

   Also contains the callback for the MITPasswordControl.

*/

/* Standard Include files */
#include <windows.h>
#include <stdio.h>
#include <string.h>

/* Private Inlclude files */
#include "leashdll.h"
#include <conf.h>
#include <leashwin.h>
#include "leash-int.h"
#include "leashids.h"
#include <leasherr.h>
#include <krb.h>
#ifndef NO_KRB5
#include <krb5.h>
#endif /* NO_KRB5 */
#include <commctrl.h>

/* Global Variables. */
static long lsh_errno;
static char *err_context;       /* error context */
extern HINSTANCE hLeashInst;
extern HINSTANCE hKrb4;
extern HINSTANCE hKrb5;


INT_PTR
CALLBACK
PasswordProc(
    HWND hwndDlg,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam
    );

INT_PTR
CALLBACK
AuthenticateProc(
    HWND hwndDlg,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam
    );

INT_PTR
CALLBACK
NewPasswordProc(
    HWND hwndDlg,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam
    );


long Leash_get_lsh_errno(LONG *err_val)
{
    return lsh_errno;
}

/*/////// ******** API Calls follow here.   ******** /////////*/

#define LEASH_DLG_MUTEX_NAME  TEXT("Leash_Dialog_Mutex")
int Leash_kinit_dlg(HWND hParent, LPLSH_DLGINFO lpdlginfo)
{
    int rc;
    HANDLE hMutex = CreateMutex(NULL, TRUE, LEASH_DLG_MUTEX_NAME);
    if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
        if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) {
            return -1;
        }
        ReleaseMutex(hMutex);
        CloseHandle(hMutex);
        return 1;   /* pretend the dialog was displayed and succeeded */
    }

    lpdlginfo->dlgtype = DLGTYPE_PASSWD;

    /* set the help file */
    Leash_set_help_file(NULL);

    /* Call the Dialog box with the DLL's Password Callback and the
       DLL's instance handle. */
    rc =  DialogBoxParam(hLeashInst, "EnterPasswordDlg", hParent,
                          PasswordProc, (LPARAM)lpdlginfo);

    ReleaseMutex(hMutex);
    CloseHandle(hMutex);
    return rc;
}


int Leash_kinit_dlg_ex(HWND hParent, LPLSH_DLGINFO_EX lpdlginfo)
{
    int rc;
    HANDLE hMutex = CreateMutex(NULL, TRUE, LEASH_DLG_MUTEX_NAME);
    if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
        if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) {
            return -1;
        }
        ReleaseMutex(hMutex);
        CloseHandle(hMutex);
        return 1;   /* pretend the dialog was displayed and succeeded */
    }

    lpdlginfo->dlgtype = DLGTYPE_PASSWD;

    /* set the help file */
    Leash_set_help_file(NULL);

    /* Call the Dialog box with the DLL's Password Callback and the
       DLL's instance handle. */
    rc = DialogBoxParam(hLeashInst, MAKEINTRESOURCE(IDD_AUTHENTICATE), hParent,
                          AuthenticateProc, (LPARAM)lpdlginfo);
    ReleaseMutex(hMutex);
    CloseHandle(hMutex);
    return rc;
}


int Leash_changepwd_dlg(HWND hParent, LPLSH_DLGINFO lpdlginfo)
{
    int rc;
    HANDLE hMutex = CreateMutex(NULL, TRUE, LEASH_DLG_MUTEX_NAME);
    if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
        if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) {
            return -1;
        }
        ReleaseMutex(hMutex);
        CloseHandle(hMutex);
        return 1;   /* pretend the dialog was displayed and succeeded */
    }

    lpdlginfo->dlgtype = DLGTYPE_CHPASSWD;

    /* Call the Dialog box with the DLL's Password Callback and the
       DLL's instance handle. */
    rc = DialogBoxParam(hLeashInst, "CHANGEPASSWORDDLG", hParent,
                          PasswordProc, (LPARAM)lpdlginfo);
    ReleaseMutex(hMutex);
    CloseHandle(hMutex);
    return rc;
}

int Leash_changepwd_dlg_ex(HWND hParent, LPLSH_DLGINFO_EX lpdlginfo)
{
    int rc;
    HANDLE hMutex = CreateMutex(NULL, TRUE, LEASH_DLG_MUTEX_NAME);
    if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
        if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) {
            return -1;
        }
        ReleaseMutex(hMutex);
        CloseHandle(hMutex);
        return 1;   /* pretend the dialog was displayed and succeeded */
    }

    lpdlginfo->dlgtype = DLGTYPE_CHPASSWD;

    /* Call the Dialog box with the DLL's Password Callback and the
       DLL's instance handle. */
    rc = DialogBoxParam(hLeashInst, MAKEINTRESOURCE(IDD_PASSWORD), hParent,
                          NewPasswordProc, (LPARAM)lpdlginfo);
    ReleaseMutex(hMutex);
    CloseHandle(hMutex);
    return rc;
}


/*  These little utils are taken from lshutil.c
    they are added here for the Call back funtion.
****** beginning of added utils from lshutil.c  ******/

BOOL IsDlgItem(HWND hWnd, WORD id)
{
    HWND hChild;

    hChild = GetDlgItem(hWnd, id);
    return hChild ? IsWindow(hChild) : 0;
}

int lsh_getkeystate(WORD keyid)
{
    static BYTE keys[256];

    GetKeyboardState((LPBYTE) &keys);
    return (int) keys[keyid];
}

LPSTR krb_err_func(int offset, long code)
{
    return pget_krb_err_txt_entry(offset);
}



/****** End of Added utils from leash.c  ******/


int PaintLogoBitmap( HANDLE hPicFrame )
{
    HBITMAP hBitmap;
    HBITMAP hOldBitmap;
    BITMAP Bitmap;
    HDC hdc, hdcMem;
    RECT rect;

    /* Invalidate the drawing space of the picframe. */
    InvalidateRect( hPicFrame, NULL, TRUE);
    UpdateWindow( hPicFrame );

    hdc = GetDC(hPicFrame);
    hdcMem = CreateCompatibleDC(hdc);
    GetClientRect(hPicFrame, &rect);
    hBitmap = LoadBitmap(hLeashInst, "LOGOBITMAP");
    hOldBitmap = SelectObject(hdcMem, hBitmap);
    GetObject(hBitmap, sizeof(Bitmap), (LPSTR) &Bitmap);
    StretchBlt(hdc, 0, 0, rect.right, rect.bottom, hdcMem, 0, 0,
               Bitmap.bmWidth, Bitmap.bmHeight, SRCCOPY);

    SelectObject(hdcMem, hOldBitmap); /* pbh 8-15-94 */
    ReleaseDC(hPicFrame, hdc);
    DeleteObject( hBitmap );  /* pbh 8-15-94 */
    DeleteDC( hdcMem );       /* pbh 8-15-94 */

    return 0;
}


/* Callback function for the Password Dialog box that initilializes and
   renews tickets. */

INT_PTR
CALLBACK
PasswordProc(
    HWND hDialog,
    UINT message,
    WPARAM wParam,
    LPARAM lParam
    )
{
    static POINT Position = { -1, -1 };
    static short state;
    int lifetime;
#define ISCHPASSWD (lpdi->dlgtype == DLGTYPE_CHPASSWD)
#define STATE_INIT     0
#define STATE_PRINCIPAL 1
#define STATE_OLDPWD   2
#define STATE_NEWPWD1  3
#define STATE_NEWPWD2  4
#define STATE_CLOSED   5
#define NEXTSTATE(newstate) SendMessage(hDialog, WM_COMMAND, ID_NEXTSTATE, newstate)
    static int ids[STATE_NEWPWD2 + 1] = {
        0,
        ID_PRINCIPAL, ID_OLDPASSWORD, ID_CONFIRMPASSWORD1,
        ID_CONFIRMPASSWORD2};
    static char principal[255], oldpassword[255], newpassword[255],
        newpassword2[255];
    static char *strings[STATE_NEWPWD2 + 1] = {
        NULL, principal, oldpassword, newpassword, newpassword2};
    static LPLSH_DLGINFO lpdi;
    char gbuf[200];                 /* global buffer for random stuff. */


#define checkfirst(id, stuff) IsDlgItem(hDialog, id) ? stuff : 0
#define CGetDlgItemText(hDlg, id, cp, len) checkfirst(id, GetDlgItemText(hDlg, id, cp, len))
#define CSetDlgItemText(hDlg, id, cp) checkfirst(id, SetDlgItemText(hDlg, id, cp))
#define CSetDlgItemInt(hDlg, id, i, b) checkfirst(id, SetDlgItemInt(hDlg, id, i, b))
#define CSendDlgItemMessage(hDlg, id, m, w, l) checkfirst(id, SendDlgItemMessage(hDlg, id, m, w, l))
#define CSendMessage(hwnd, m, w, l) IsWindow(hwnd) ? SendMessage(hwnd, m, w, l) : 0
#define CShowWindow(hwnd, state) IsWindow(hwnd) ? ShowWindow(hwnd, state) : 0

#define GETITEMTEXT(id, cp, maxlen) \
  GetDlgItemText(hDialog, id, (LPSTR)(cp), maxlen)
#define CloseMe(x) SendMessage(hDialog, WM_COMMAND, ID_CLOSEME, x)


#define EDITFRAMEIDOFFSET               500

    switch (message) {

    case WM_INITDIALOG:

        *( (LPLSH_DLGINFO far *)(&lpdi) ) = (LPLSH_DLGINFO)(LPSTR)lParam;
        lpdi->dlgstatemax = ISCHPASSWD ? STATE_NEWPWD2
            : STATE_OLDPWD;
        SetWindowText(hDialog, lpdi->title);
        /* stop at old password for normal password dlg */

        SetProp(hDialog, "HANDLES_HELP", (HANDLE)1);

        if (lpdi->principal)
            lstrcpy(principal, lpdi->principal);
        else
    	{
            principal[0] = '\0';
            /* is there a principal already being used? if so, use it. */
	    }

        CSetDlgItemText(hDialog, ID_PRINCIPAL, principal);

        lifetime = Leash_get_default_lifetime();
        if (lifetime <= 0)
            lifetime = 600; /* 10 hours */

        CSetDlgItemInt(hDialog, ID_DURATION, lifetime, FALSE);

        /* setup text of stuff. */

        if (Position.x > 0 && Position.y > 0 &&
            Position.x < GetSystemMetrics(SM_CXSCREEN) &&
            Position.y < GetSystemMetrics(SM_CYSCREEN))
            SetWindowPos(hDialog, 0, Position.x, Position.y, 0, 0, 
                         SWP_NOSIZE | SWP_NOZORDER);

        /* set window pos to last saved window pos */


        /* replace standard edit control with our own password edit
           control for password entry. */
        {
            RECT r;
            POINT pxy, psz;
            HWND hwnd;
            int i;

            for (i = ID_OLDPASSWORD; i <= ids[lpdi->dlgstatemax]; i++)
            {
                hwnd = GetDlgItem(hDialog, i);
                GetWindowRect(hwnd, &r);
                psz.x = r.right - r.left;
                psz.y = r.bottom - r.top;

                pxy.x = r.left; pxy.y = r.top;
                ScreenToClient(hDialog, &pxy);

                /* create a substitute window: */

                DestroyWindow(hwnd);
                /* kill off old edit window. */

                CreateWindow(MIT_PWD_DLL_CLASS,	/* our password window :o] */
                             "",		/* no text */
                             WS_CHILD | WS_VISIBLE | WS_TABSTOP, /* child window, visible,tabstop */
                             pxy.x, pxy.y,	/* x, y coords */
                             psz.x, psz.y,	/* width, height */
                             hDialog,		/* the parent */
                             (HMENU)i,		/* same id *//* id offset for the frames */
                             (HANDLE)hLeashInst,/* instance handles */
                             NULL);		/* createstruct */
            }
        }

        state = STATE_INIT;
        NEXTSTATE(STATE_PRINCIPAL);
        break;

    case WM_PAINT:
        PaintLogoBitmap( GetDlgItem(hDialog, ID_PICFRAME) );
        break;

    case WM_COMMAND:
        switch (wParam) {
        case ID_HELP:
	{
            WinHelp(GetWindow(hDialog,GW_OWNER), KRB_HelpFile, HELP_CONTEXT,
                    ISCHPASSWD ? ID_CHANGEPASSWORD : ID_INITTICKETS);
	}
	break;
        case ID_CLOSEME:
	{
            int i;

            for (i = STATE_PRINCIPAL; i <= lpdi->dlgstatemax; i++)
	    {
                memset(strings[i], '\0', 255);
                SetDlgItemText(hDialog, ids[i], "");
	    }
            /* I claim these passwords in the name
               of planet '\0'... */

            RemoveProp(hDialog, "HANDLES_HELP");
            state = STATE_CLOSED;
            EndDialog(hDialog, (int)lParam);
        return TRUE;
	}
	break;
        case ID_DURATION:
            break;
        case ID_PRINCIPAL:
        case ID_OLDPASSWORD:
        case ID_CONFIRMPASSWORD1:
        case ID_CONFIRMPASSWORD2:
            if (HIWORD(lParam) == EN_SETFOCUS)
            {
                /* nothing, for now. */
            }
            break;
        case ID_NEXTSTATE:
	{
            RECT rbtn, redit;
            POINT p;
            int idfocus, i, s;
            HWND hfocus, hbtn;
            int oldstate = state;

            state = (int)lParam;
            idfocus = ids[state];

#ifdef ONE_NEWPWDBOX
            if (state == STATE_NEWPWD2)
                SendDlgItemMessage(hDialog, ID_CONFIRMPASSWORD1, WM_SETTEXT,
                                   0, (LONG)(LPSTR)"");
#endif

            for (s = STATE_PRINCIPAL; s <= lpdi->dlgstatemax; s++)
	    {
                i = ids[s];

                if (s > state)
                    SendDlgItemMessage(hDialog, i, WM_SETTEXT, 0,
                                       (LONG)(LPSTR)"");
                EnableWindow(GetDlgItem(hDialog, i), i == idfocus);
                ShowWindow(GetDlgItem(hDialog, i),
                           (i <= idfocus ? SW_SHOW : SW_HIDE));
                /* ShowWindow(GetDlgItem(hDialog, i + CAPTION_OFFSET),
                   (i <= idfocus ? SW_SHOW : SW_HIDE));*/
                /* show caption? */
	    }
#ifdef ONE_NEWPWDBOX
            CSetDlgItemText(hDialog, ID_CONFIRMCAPTION1,
                            state < STATE_NEWPWD2 ?
                            "Enter new password:" :
                            "Enter new password again:");
            if (state == STATE_NEWPWD2)
	    {
                HWND htext;
                htext = GetDlgItem(hDialog, ID_CONFIRMCAPTION1);
                FlashAnyWindow(htext);
                WinSleep(50);
                FlashAnyWindow(htext);
	    }
#endif

            hfocus = GetDlgItem(hDialog, idfocus);
            if ( hfocus != (HWND)NULL ){
                SetFocus(hfocus); /* switch focus */
                if (idfocus >= ID_OLDPASSWORD)
                    SendMessage(hfocus, WM_SETTEXT, 0, (LPARAM) (LPSTR) "");
                else
                {
                    SendMessage(hfocus, EM_SETSEL, 0, MAKELONG(0, -1));
                }
                GetWindowRect(hfocus, &redit);
            }

            hbtn   = GetDlgItem(hDialog, IDOK);
            if( IsWindow(hbtn) ){
                GetWindowRect(hbtn, &rbtn);
                p.x = rbtn.left; p.y = redit.top;
                ScreenToClient(hDialog, &p);

                SetWindowPos(hbtn, 0, p.x, p.y, 0, 0,
                             SWP_NOSIZE | SWP_NOZORDER);
            }
	}
	break;
        case IDOK:
	{
	    char* p_Principal;
        DWORD value = 0;

	    GETITEMTEXT(ids[state], (LPSTR)strings[state], 255);

            switch(state)
            {
            case STATE_PRINCIPAL:
            {
                if (!principal[0])
                {
                    MessageBox(hDialog, 
                                "You are not allowed to enter a blank principal.",
                               "Invalid Principal",
                               MB_OK | MB_ICONSTOP);
                    NEXTSTATE(STATE_PRINCIPAL);
                    return TRUE;
                }

	        // Change 'principal' to upper case after checking
	        // "UpperCase" value in the Registry
                p_Principal = strchr(principal, '@');

                if (p_Principal && Leash_get_default_uppercaserealm())
                    strupr(p_Principal);
                break;
            }
	    case STATE_OLDPWD:
            {
		int duration;

		if (!ISCHPASSWD)
                    duration = GetDlgItemInt(hDialog, ID_DURATION, 0, FALSE);
                if (!oldpassword[0])
                {
                    MessageBox(hDialog, "You are not allowed to enter a "
                               "blank password.",
                               "Invalid Password",
                               MB_OK | MB_ICONSTOP);
                    NEXTSTATE(STATE_OLDPWD);
                    return TRUE;
                }
                if (lpdi->dlgtype == DLGTYPE_CHPASSWD)
                    lsh_errno = Leash_int_checkpwd(principal, oldpassword, 1);
                else
                {
                    lsh_errno = Leash_int_kinit_ex( 0,
                                                    hDialog,
                                                    principal,
                                                    oldpassword, 
                                                    duration,
                                                    Leash_get_default_forwardable(),
                                                    Leash_get_default_proxiable(),
                                                    Leash_get_default_renew_till(),
                                                    Leash_get_default_noaddresses(),
                                                    Leash_get_default_publicip(),
                                                    1
                                                    );
                }
		if (lsh_errno != 0)
                {
		    int next_state = state;
		    int capslock;
		    LONG check_time;
		    char *cp;

		    err_context = "";

		    switch(lsh_errno)
                    {
                    case LSH_INVPRINCIPAL:
                    case LSH_INVINSTANCE:
                    case LSH_INVREALM:
                    case KRBERR(KDC_PR_UNKNOWN):
			next_state = STATE_PRINCIPAL;
			break;
                    case KRBERR(RD_AP_TIME):
                    case KRBERR(KDC_SERVICE_EXP):
                        check_time = Leash_timesync(1);
                        if( check_time == 0 ){
                            next_state = STATE_PRINCIPAL;
                            SendMessage(hDialog, WM_COMMAND, IDOK, state);
                            return(TRUE);
                        } else {
                            next_state = STATE_PRINCIPAL;
                            lsh_errno = check_time;
                            return(TRUE);
                        }
                        break;
                    }
		    capslock = lsh_getkeystate(VK_CAPITAL);
                    /* low-order bit means caps lock is
                       toggled; if so, warn user since there's
                       been an error. */
		    if (capslock & 1)
                    {
			lstrcpy((LPSTR)gbuf, (LPSTR)err_context);
			cp = gbuf + lstrlen((LPSTR)gbuf);
			if (cp != gbuf)
                            *cp++ = ' ';
			lstrcpy(cp, "(This may be because your CAPS LOCK key is down.)");
			err_context = gbuf;
                    }

// XXX		    DoNiftyErrorReport(lsh_errno, ISCHPASSWD ? ""
// XXX				       : "Ticket initialization failed.");
		    NEXTSTATE(next_state);
		    return TRUE;
                }
		if (ISCHPASSWD)
                    break;
		CloseMe(TRUE); /* success */
            }
            break;
	    case STATE_NEWPWD1:
            {
                int i = 0;
                int bit8 = 0;

                for( i = 0; i < 255; i++ ){
                    if( newpassword[i] == '\0' ){
                        if ( bit8 ) {
                            MessageBox(hDialog, 
                                        "Passwords should not contain non-ASCII characters.",
                                        "Internationalization Warning",
                                        MB_OK | MB_ICONINFORMATION);
                        }
                        i = 255;
                        break;
                    } else if( !isprint(newpassword[i]) ){
                        memset(newpassword, '\0', 255);
                        /* I claim these passwords in the name of planet '\0'... */
                        MessageBox(hDialog, 
                                   "Passwords may not contain non-printable characters.",
                                    "Invalid Password",
                                    MB_OK | MB_ICONSTOP);
                        NEXTSTATE(STATE_NEWPWD1);
                        return TRUE;
                    } else if ( newpassword[i] > 127 )
                        bit8 = 1;
                }
            }
            break;
	    case STATE_NEWPWD2:
                if (lstrcmp(newpassword, newpassword2))
                {
                    NEXTSTATE(STATE_NEWPWD1);
                    MessageBox(hDialog, 
                                "The new password was not entered the same way twice.",
                                "Password validation error",
                                MB_OK | MB_ICONSTOP);
                    return TRUE;
                }
                else
                {
                    /* make them type both pwds again if error */
                    int next_state = STATE_NEWPWD1;
                    int capslock;
                    char *cp;

                    capslock = lsh_getkeystate(VK_CAPITAL);
                    /* low-order bit means caps lock is
                       toggled; if so, warn user since there's
                       been an error. */
                    if (capslock & 1)
                    {
                        lstrcpy((LPSTR)gbuf, (LPSTR)err_context);
                        cp = gbuf + lstrlen((LPSTR)gbuf);
                        if (cp != gbuf)
                            *cp++ = ' ';
                        lstrcpy(cp, "(This may be because your CAPS LOCK key is down.)");
                        err_context = gbuf;
                    }

                    if ((lsh_errno =
                         Leash_int_changepwd(principal, oldpassword,
                                         newpassword, 0, 1))
                        == 0){
                        CloseMe(TRUE);
                    }
                    else {
                        // XXX - DoNiftyErrorReport(lsh_errno, "Error while changing password.");
                        NEXTSTATE(next_state);
                        return TRUE;

                    }
		}
                break;
	    }
            /* increment state, but send the old state as a
               parameter */
            SendMessage(hDialog, WM_COMMAND, ID_NEXTSTATE, state + 1);
	}
	break;
        case IDCANCEL:
            CloseMe(FALSE);
            break;
        case ID_RESTART:
	{
            int i;

            for (i = ID_OLDPASSWORD; i <= ids[lpdi->dlgstatemax]; i++)
                SetDlgItemText(hDialog, i, "");
            SendMessage(hDialog, WM_COMMAND, ID_NEXTSTATE,
                        STATE_PRINCIPAL);
	}
	break;
        }
        break;

    case WM_MOVE:
        if (state != STATE_CLOSED)
#ifdef _WIN32
#define LONG2POINT(l,pt) ((pt).x=(SHORT)LOWORD(l),  \
			  (pt).y=(SHORT)HIWORD(l))
            LONG2POINT(lParam,Position);
#else
        Position = MAKEPOINT(lParam);
#endif
        break;
    }
    return FALSE;
}


#define KRB_FILE                "KRB.CON"
#define KRBREALM_FILE           "KRBREALM.CON"
#define KRB5_FILE               "KRB5.INI"

BOOL 
GetProfileFile(
    LPSTR confname, 
    UINT szConfname
    )
{
    char **configFile = NULL;
    if (hKrb5 &&
		pkrb5_get_default_config_files(&configFile)) 
    {
        GetWindowsDirectory(confname,szConfname);
        confname[szConfname-1] = '\0';
		strncat(confname, "\\",sizeof(confname)-strlen(confname));
        confname[szConfname-1] = '\0';
		strncat(confname, KRB5_FILE,sizeof(confname)-strlen(confname));
        confname[szConfname-1] = '\0';
        return FALSE;
    }
    
    *confname = 0;
    
    if (hKrb5 && configFile)
    {
        strncpy(confname, *configFile, szConfname);
        pkrb5_free_config_files(configFile); 
    }
    
    if (!*confname)
    {
        GetWindowsDirectory(confname,szConfname);
        confname[szConfname-1] = '\0';
		strncat(confname, "\\",sizeof(confname)-strlen(confname));
        confname[szConfname-1] = '\0';
		strncat(confname, KRB5_FILE,sizeof(confname)-strlen(confname));
        confname[szConfname-1] = '\0';
    }
    
    return FALSE;
}

BOOL
GetKrb4ConFile(
    LPSTR confname, 
    UINT szConfname
    )
{
    if (hKrb5 && !hKrb4)
	{ // hold krb.con where krb5.ini is located
		CHAR krbConFile[MAX_PATH]="";
		LPSTR pFind;

	    //strcpy(krbConFile, CLeashApp::m_krbv5_profile->first_file->filename);
        if (GetProfileFile(krbConFile, sizeof(krbConFile)))	
        {
		    GetWindowsDirectory(krbConFile,sizeof(krbConFile));
            krbConFile[MAX_PATH-1] = '\0';
			strncat(krbConFile, "\\",sizeof(krbConFile)-strlen(krbConFile));
            krbConFile[MAX_PATH-1] = '\0';
			strncat(krbConFile, KRB5_FILE,sizeof(krbConFile)-strlen(krbConFile));
            krbConFile[MAX_PATH-1] = '\0';
        }

		pFind = strrchr(krbConFile, '\\');
		if (pFind)
		{
			*pFind = 0;
			strncat(krbConFile, "\\",sizeof(krbConFile)-strlen(krbConFile));
            krbConFile[MAX_PATH-1] = '\0';
			strncat(krbConFile, KRB_FILE,sizeof(krbConFile)-strlen(krbConFile));
            krbConFile[MAX_PATH-1] = '\0';
		}
		else
			krbConFile[0] = 0;
		
		strncpy(confname, krbConFile, szConfname);
        confname[szConfname-1] = '\0';
	}
	else if (hKrb4)
	{ 
        unsigned int size = szConfname;
        memset(confname, '\0', szConfname);
 		if (!pkrb_get_krbconf2(confname, &size))
		{ // Error has happened
		    GetWindowsDirectory(confname,szConfname);
            confname[szConfname-1] = '\0';
			strncat(confname, "\\",szConfname-strlen(confname));
            confname[szConfname-1] = '\0';
			strncat(confname,KRB_FILE,szConfname-strlen(confname));
            confname[szConfname-1] = '\0';
		}
	}
    return FALSE;
}

BOOL
GetKrb4RealmFile(
    LPSTR confname, 
    UINT szConfname
    )
{
    if (hKrb5 && !hKrb4)
	{ // hold krb.con where krb5.ini is located
		CHAR krbRealmConFile[MAX_PATH];
		LPSTR pFind;

		//strcpy(krbRealmConFile, CLeashApp::m_krbv5_profile->first_file->filename);
		if (GetProfileFile(krbRealmConFile, sizeof(krbRealmConFile)))	
        {
		    GetWindowsDirectory(krbRealmConFile,sizeof(krbRealmConFile));
            krbRealmConFile[MAX_PATH-1] = '\0';
			strncat(krbRealmConFile, "\\",sizeof(krbRealmConFile)-strlen(krbRealmConFile));
            krbRealmConFile[MAX_PATH-1] = '\0';
			strncat(krbRealmConFile, KRB5_FILE,sizeof(krbRealmConFile)-strlen(krbRealmConFile));
            krbRealmConFile[MAX_PATH-1] = '\0';
        }

		pFind = strrchr(krbRealmConFile, '\\');
		if (pFind)
		{
			*pFind = 0;
			strncat(krbRealmConFile, "\\", sizeof(krbRealmConFile)-strlen(krbRealmConFile));
            krbRealmConFile[MAX_PATH-1] = '\0';
			strncat(krbRealmConFile, KRBREALM_FILE, sizeof(krbRealmConFile)-strlen(krbRealmConFile));
            krbRealmConFile[MAX_PATH-1] = '\0';
		}
		else
			krbRealmConFile[0] = 0;
		
		strncpy(confname, krbRealmConFile, szConfname);
        confname[szConfname-1] = '\0';
	}
	else if (hKrb4)
	{ 
        unsigned int size = szConfname;
        memset(confname, '\0', szConfname);
        if (!pkrb_get_krbrealm2(confname, &size))
		{ 
		    GetWindowsDirectory(confname,szConfname);
            confname[szConfname-1] = '\0';
			strncat(confname, "\\",szConfname-strlen(confname));
            confname[szConfname-1] = '\0';
			strncat(confname,KRBREALM_FILE,szConfname-strlen(confname));
            confname[szConfname-1] = '\0';
            return TRUE;
		}
	}	
    return FALSE;
}

static BOOL
FindDLLName(CHAR * filename, UINT len)
{
    if ( !filename || len == 0 )
        return 0;

    filename[0] = 0;

    if ( pEnumProcessModules ) {
        char checkName[1024];
        HMODULE hMods[1024];
        HANDLE hProcess;
        DWORD cbNeeded;
        unsigned int i;

        /* Get a list of all the modules in this process. */
        hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId());

        if (pEnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
        {
            for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
            {
                char szModName[2048];

                /* Get the full path to the module's file. */
                if (pGetModuleFileNameEx(hProcess, hMods[i], szModName, sizeof(szModName)))
                {
                    lstrcpyn(checkName, szModName, sizeof(checkName));
                    strupr(checkName);

                    if (strstr(checkName, "LEASHW32")) {
                        lstrcpyn(filename, checkName, len);
                        break;
                    }
                }
            }
        }   

        CloseHandle(hProcess);
    } else if (pCreateToolhelp32Snapshot && pModule32First && pModule32Next ) {
        char checkName[1024];
        MODULEENTRY32 me32 = {0};
        HANDLE hProcessSnap = NULL;

        hProcessSnap = pCreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
        if (hProcessSnap == (HANDLE)-1)
            return FALSE;

        me32.dwSize = sizeof(MODULEENTRY32);
        if (pModule32First(hProcessSnap, &me32))
        {
            do
            {
                lstrcpyn(checkName, me32.szExePath, sizeof(checkName));
                strupr(checkName);

                if (strstr(checkName, "LEASHW32")) {
                    lstrcpyn(filename, checkName, len);
                    break;
                }
            }
            while (pModule32Next(hProcessSnap, &me32));
        }
    }

    return filename[0] ? 1 : 0;
}   

static DWORD
SetVersionInfo(
    HWND hDialog,
    UINT id_version,
    UINT id_copyright
    )
{
    CHAR filename[1024];
    DWORD dwVersionHandle;
    LPVOID pVersionInfo = 0;
    DWORD retval = 0;
    LPDWORD pLangInfo = 0;
    LPTSTR szVersion = 0;
    LPTSTR szCopyright = 0;
    UINT len = 0;
    CHAR sname_version[] = "FileVersion";
    CHAR sname_copyright[] = "LegalCopyright";
    CHAR szVerQ[(sizeof("\\StringFileInfo\\12345678\\") +
                  max(sizeof(sname_version) / sizeof(CHAR),
                      sizeof(sname_copyright) / sizeof(CHAR)))];
    CHAR szVerCopy[128] = "";
    CHAR * cp = szVerQ;
    DWORD size;

    if (!FindDLLName(filename, sizeof(filename)))
        return GetLastError();

    size = GetFileVersionInfoSize(filename, &dwVersionHandle);

    if (!size)
        return GetLastError();

    pVersionInfo = malloc(size);
    if (!pVersionInfo)
        return ERROR_NOT_ENOUGH_MEMORY;

    if (!GetFileVersionInfo(filename, dwVersionHandle, size, pVersionInfo))
    {
        retval = GetLastError();
        goto cleanup;
    }

    if (!VerQueryValue(pVersionInfo, "\\VarFileInfo\\Translation",
                       (LPVOID*)&pLangInfo, &len))
    {
        retval = GetLastError();
        goto cleanup;
    }


    cp += wsprintf(szVerQ,
                   "\\StringFileInfo\\%04x%04x\\",
                   LOWORD(*pLangInfo), HIWORD(*pLangInfo));

    lstrcpy(cp, sname_version);
    if (!VerQueryValue(pVersionInfo, szVerQ, (LPVOID*)&szVersion, &len))
    {
        retval = GetLastError() || ERROR_NOT_ENOUGH_MEMORY;
        goto cleanup;
    }

    lstrcpy(cp, sname_copyright);
    if (!VerQueryValue(pVersionInfo, szVerQ, (LPVOID*)&szCopyright, &len))
    {
        retval = GetLastError() || ERROR_NOT_ENOUGH_MEMORY;
        goto cleanup;
    }

    if ( strlen(szVersion) < sizeof(szVerCopy) - 8 ) {
        wsprintf(szVerCopy, "Version %s", szVersion);
        szVerCopy[sizeof(szVerCopy) - 1] = 0;

        SetWindowText(GetDlgItem(hDialog,id_version),szVerCopy);
    }
    SetWindowText(GetDlgItem(hDialog,id_copyright),szCopyright);

 cleanup:
    if (pVersionInfo)
        free(pVersionInfo);
    return retval;
}


int
readstring(FILE * file, char * buf, int len)
{
	int  c,i;
	memset(buf, '\0', sizeof(buf));
	for (i=0, c=fgetc(file); c != EOF ; c=fgetc(file), i++)
	{	
		if (i < sizeof(buf)) {
			if (c == '\n') {
				buf[i] = '\0';
				return i;
			} else {
				buf[i] = c;
			}
		} else {
			if (c == '\n') {
				buf[len-1] = '\0';
				return(i);
			}
		}
	}
	if (c == EOF) {
		if (i > 0 && i < len) {
			buf[i] = '\0';
			return(i);
		} else {
			buf[len-1] = '\0';
			return(-1);
		}
	}
    return(-1);
}

typedef struct _slider_info {
	int slider_id;
	int text_id;
	int min;
	int max;
	int increment;
	struct _slider_info * next;
} slider_info;
static slider_info * sliders = NULL;

static slider_info *
FreeSlider(slider_info * s)
{	
	slider_info * n = NULL;

	if (s) {
		n = s->next;
		free(s);
	}
	return n;
}

static void
CleanupSliders(void)
{
	while(sliders)
		sliders = FreeSlider(sliders);
}


static unsigned short
NewSliderValue(HWND hDialog, int id)
{
	int value = 0;
	slider_info * s = sliders;
	while(s) {
		if (s->slider_id == id) {
			int pos = CSendDlgItemMessage( hDialog, id,
										 TBM_GETPOS,
										 (WPARAM) 0, (LPARAM) 0);  
			value = s->min + (pos * s->increment);
			break;
		}
		s = s->next;
	}
	return(value);
}

static const char *
NewSliderString(int id, int pos)
{
	static char buf[64]="";
	char * p = buf;
	int value = 0;
	int must_hours = 0;
	slider_info * s = sliders;
	while(s) {
		if (s->slider_id == id) {
			value = s->min + pos * s->increment;
			*p = 0;
			if (value >= 60 * 24) {
				sprintf(p,"%d day(s) ",value / (60 * 24));
				value %= (60 * 24);
				p += strlen(p);
				must_hours = 1;
			}
			if (must_hours || value >= 60) {
				sprintf(p,"%d hour(s) ",value / 60);
				value %= 60;
				p += strlen(p);
			}
			sprintf(p,"%d minute(s) ",value);
			break;
		}
		s = s->next;
	}
	return(buf);
}

static void 
SetupSlider( HWND hDialog, 
			 int sliderID,
			 int textFieldID,
			 int minimum,
			 int maximum,
			 int value)
{
    int min = minimum;
    int max = maximum;
    int increment = 0;
    int range;
	int roundedMinimum;
	int roundedMaximum;
	int roundedValue;
	slider_info * new_info;

    if (max < min) {
        // swap values
        int temp = max;
        max = min;
        min = temp;
    }
	range = max - min;

    if (range < 5*60)             { increment = 1;       //  1 s if under   5 m
    } else if (range < 30*60)     { increment = 5;       //  5 s if under  30 m
    } else if (range < 60*60)     { increment = 15;      // 15 s if under   1 h
    } else if (range < 2*60*60)   { increment = 30;      // 30 s if under   2 h
    } else if (range < 5*60*60)   { increment = 60;      //  1 m if under   5 h
    } else if (range < 50*60*60)  { increment = 5*60;    //  5 m if under  50 h
    } else if (range < 200*60*60) { increment = 15*60;   // 15 m if under 200 h
    } else if (range < 500*60*60) { increment = 30*60;   // 30 m if under 500 h
    } else                        { increment = 60*60; } //  1 h otherwise

    roundedMinimum = (min / increment) * increment;
    if (roundedMinimum > min) { roundedMinimum -= increment; }
    if (roundedMinimum <= 0)  { roundedMinimum += increment; } // make positive

    roundedMaximum = (max / increment) * increment;
    if (roundedMaximum < max) { roundedMaximum += increment; }

    roundedValue = (value / increment) * increment;
    if (roundedValue < roundedMinimum) { roundedValue = roundedMinimum; }
    if (roundedValue > roundedMaximum) { roundedValue = roundedMaximum; }

    if (roundedMinimum == roundedMaximum) {
        // [textField setTextColor: [NSColor grayColor]];
		EnableWindow(GetDlgItem(hDialog,sliderID),FALSE);
    } else {
        // [textField setTextColor: [NSColor blackColor]];
		EnableWindow(GetDlgItem(hDialog,sliderID),TRUE);
    }

	CSendDlgItemMessage( hDialog, sliderID, 
						 TBM_SETRANGEMIN,
						 (WPARAM) FALSE, 
						 (LPARAM) 0 );
	CSendDlgItemMessage( hDialog, sliderID, 
						 TBM_SETRANGEMAX,
						 (WPARAM) FALSE, 
						 (LPARAM) (roundedMaximum - roundedMinimum) / increment );
	CSendDlgItemMessage( hDialog, sliderID, 
						 TBM_SETPOS,
						 (WPARAM) TRUE, 
						 (LPARAM) (roundedValue - roundedMinimum) / increment);

	new_info = (slider_info *) malloc(sizeof(slider_info));
	new_info->slider_id = sliderID;
	new_info->text_id = textFieldID;
	new_info->min = roundedMinimum;
	new_info->max = roundedMaximum;
	new_info->increment = increment;
	new_info->next = sliders;
	sliders = new_info;

	SetWindowText(GetDlgItem(hDialog, textFieldID),
				   NewSliderString(sliderID,(roundedValue - roundedMinimum) / increment));
}


static void
AdjustOptions(HWND hDialog, int show, int hideDiff)
{
    RECT rect;
    RECT dlgRect;
    HWND hwnd;
    int diff;

    Leash_set_hide_kinit_options(!show);

    ShowWindow(GetDlgItem(hDialog,IDC_STATIC_LIFETIME),show);
    ShowWindow(GetDlgItem(hDialog,IDC_STATIC_LIFETIME_VALUE),show);
    ShowWindow(GetDlgItem(hDialog,IDC_SLIDER_LIFETIME),show);
    ShowWindow(GetDlgItem(hDialog,IDC_SLIDER_RENEWLIFE),show);
    ShowWindow(GetDlgItem(hDialog,IDC_STATIC_RENEW),show);
    ShowWindow(GetDlgItem(hDialog,IDC_STATIC_RENEW_TILL_VALUE),show);
    ShowWindow(GetDlgItem(hDialog,IDC_CHECK_FORWARDABLE),show);
    ShowWindow(GetDlgItem(hDialog,IDC_CHECK_NOADDRESS),show);
    ShowWindow(GetDlgItem(hDialog,IDC_CHECK_RENEWABLE),show);
    ShowWindow(GetDlgItem(hDialog,IDC_STATIC_KRB5),show);

    GetWindowRect( hDialog, &dlgRect );
    diff = dlgRect.top + GetSystemMetrics(SM_CYCAPTION) 
         + GetSystemMetrics(SM_CYDLGFRAME) + (show ? -1 : 1) * hideDiff;

    hwnd = GetDlgItem(hDialog,IDOK);
    GetWindowRect(hwnd,&rect);
    SetWindowPos(hwnd,0,rect.left-dlgRect.left-GetSystemMetrics(SM_CXDLGFRAME),rect.top-diff,0,0,SWP_NOZORDER|SWP_NOSIZE);
    hwnd = GetDlgItem(hDialog,IDCANCEL);
    GetWindowRect(hwnd,&rect);
    SetWindowPos(hwnd,0,rect.left-dlgRect.left-GetSystemMetrics(SM_CXDLGFRAME),rect.top-diff,0,0,SWP_NOZORDER|SWP_NOSIZE);
    hwnd = GetDlgItem(hDialog,IDC_BUTTON_OPTIONS);
    GetWindowRect(hwnd,&rect);
    SetWindowPos(hwnd,0,rect.left-dlgRect.left-GetSystemMetrics(SM_CXDLGFRAME),rect.top-diff,0,0,SWP_NOZORDER|SWP_NOSIZE);
    hwnd = GetDlgItem(hDialog,IDC_STATIC_VERSION);
    GetWindowRect(hwnd,&rect);
    SetWindowPos(hwnd,0,rect.left-dlgRect.left-GetSystemMetrics(SM_CXDLGFRAME),rect.top-diff,0,0,SWP_NOZORDER|SWP_NOSIZE);
    hwnd = GetDlgItem(hDialog,IDC_STATIC_COPYRIGHT);
    GetWindowRect(hwnd,&rect);
    SetWindowPos(hwnd,0,rect.left-dlgRect.left-GetSystemMetrics(SM_CXDLGFRAME),rect.top-diff,0,0,SWP_NOZORDER|SWP_NOSIZE);
    SetWindowPos(hDialog,0,0,0,
                 dlgRect.right-dlgRect.left,
                 dlgRect.bottom-dlgRect.top+(show ? 1 : - 1) * hideDiff,
                 SWP_NOZORDER|SWP_NOMOVE);

    CSetDlgItemText(hDialog, IDC_BUTTON_OPTIONS, show ? "Hide Options" : "Show Options");

}


/* Callback function for the Authentication Dialog box that initializes and
   renews tickets. */

INT_PTR
CALLBACK
AuthenticateProc(
    HWND hDialog,
    UINT message,
    WPARAM wParam,
    LPARAM lParam
    )
{
    static POINT Position = { -1, -1 };
    static char username[LEASH_USERNAME_SZ]="";
	static char realm[LEASH_REALM_SZ]="";
	static char password[256]="";
	static int  lifetime=0;
	static int  renew_till=0;
	static int  forwardable=0;
	static int  noaddresses=0;
	static int  proxiable=0;
	static int  publicip=0;
    static LPLSH_DLGINFO_EX lpdi;
	static HWND hDlg=0;
	static HWND hSliderLifetime=0;
	static HWND hSliderRenew=0;
    static RECT dlgRect;
    static int  hideDiff = 0;
    char gbuf[256];                 /* global buffer for random stuff. */
	char principal[256];
	long realm_count = 0;
    int disable_noaddresses = 0;

    switch (message) {

    case WM_INITDIALOG:
		hDlg = hDialog;

        SetVersionInfo(hDialog,IDC_STATIC_VERSION,IDC_STATIC_COPYRIGHT);
		hSliderLifetime = GetDlgItem(hDialog, IDC_STATIC_LIFETIME_VALUE);
		hSliderRenew = GetDlgItem(hDialog, IDC_STATIC_RENEW_TILL_VALUE);

        *( (LPLSH_DLGINFO_EX far *)(&lpdi) ) = (LPLSH_DLGINFO_EX)(LPSTR)lParam;

		if ((lpdi->size != LSH_DLGINFO_EX_V1_SZ && 
             lpdi->size < sizeof(LSH_DLGINFO_EX)) ||
			lpdi->dlgtype != DLGTYPE_PASSWD) {

			MessageBox(hDialog, "An incorrect initialization data structure was provided.",
						"AuthenticateProc()",
						MB_OK | MB_ICONSTOP);
			return FALSE;
		}

        if ( lpdi->size >= sizeof(LSH_DLGINFO_EX) ) {
            lpdi->out.username[0] = 0;
            lpdi->out.realm[0] = 0;
        }

        SetWindowText(hDialog, lpdi->title);

        SetProp(hDialog, "HANDLES_HELP", (HANDLE)1);

        if (lpdi->username)
            lstrcpy(username, lpdi->username);
		if (lpdi->realm)
			lstrcpy(realm, lpdi->realm);
		if (lpdi->use_defaults) {
			lifetime = Leash_get_default_lifetime();
			if (lifetime <= 0)
				lifetime = 600; /* 10 hours */
			if (Leash_get_default_renewable()) {
                renew_till = Leash_get_default_renew_till();
                if (renew_till < 0)
                    renew_till = 10800; /* 7 days */
            } else 
                renew_till = 0;
			forwardable = Leash_get_default_forwardable();
			if (forwardable < 0)
				forwardable = 0;
			noaddresses = Leash_get_default_noaddresses();
			if (noaddresses < 0)
				noaddresses = 0;
			proxiable = Leash_get_default_proxiable();
			if (proxiable < 0)
				proxiable = 0;
			publicip = Leash_get_default_publicip();
			if (publicip < 0)
				publicip = 0;
		} else {
			forwardable = lpdi->forwardable;
			noaddresses = lpdi->noaddresses;
			lifetime = lpdi->lifetime;
			renew_till = lpdi->renew_till;
			proxiable = lpdi->proxiable;
			publicip = lpdi->publicip;
		}

        CSetDlgItemText(hDialog, IDC_EDIT_PRINCIPAL, username);
        CSetDlgItemText(hDialog, IDC_EDIT_PASSWORD, "");

#if 0  /* 20030619 - mjv wishes to return to the default character */
        /* echo spaces */
		CSendDlgItemMessage(hDialog, IDC_EDIT_PASSWORD, EM_SETPASSWORDCHAR, 32, 0);
#endif

		/* Populate list of Realms */
		CSendDlgItemMessage(hDialog, IDC_COMBO_REALM, CB_RESETCONTENT, 0, 0);
		CSendDlgItemMessage(hDialog, IDC_COMBO_REALM, CB_LIMITTEXT, 192, 0);

		if (pprofile_get_subsection_names && pprofile_free_list) {
			const char*  rootSection[] = {"realms", NULL};
			const char** rootsec = rootSection;
			char **sections = NULL, **cpp = NULL, *value = NULL;

			char krb5_conf[MAX_PATH+1];

			if (!GetProfileFile(krb5_conf,sizeof(krb5_conf))) {
				profile_t profile;
				long retval;
				const char *filenames[2];

				filenames[0] = krb5_conf;
				filenames[1] = NULL;
				retval = pprofile_init(filenames, &profile);
				if (!retval) {
					retval = pprofile_get_subsection_names(profile,	rootsec, &sections);

					if (!retval)
					{
						for (cpp = sections; *cpp; cpp++)
						{
							CSendDlgItemMessage(hDialog, IDC_COMBO_REALM, CB_ADDSTRING, 0, (LPARAM)*cpp);
							realm_count++;
						}
					}
					pprofile_free_list(sections);

                    retval = pprofile_get_string(profile, "libdefaults","noaddresses", 0, "true", &value);
                    if ( value ) {
                        disable_noaddresses = config_boolean_to_int(value);
                        pprofile_release_string(value);
                    }

					pprofile_release(profile);
				}
			}
		} else {
			FILE * file;
			char krb_conf[MAX_PATH+1];
			char * p;

			if (!GetKrb4ConFile(krb_conf,sizeof(krb_conf)) && 
				(file = fopen(krb_conf, "rt")))
			{
				char lineBuf[256];
				// Skip the default realm
				readstring(file,lineBuf,sizeof(lineBuf));

				// Read the defined realms
				while (TRUE)
				{
					if (readstring(file,lineBuf,sizeof(lineBuf)) < 0)
						break;

					if (*(lineBuf + strlen(lineBuf) - 1) == '\r')
						*(lineBuf + strlen(lineBuf) - 1) = 0;

					for (p=lineBuf; *p ; p++)
					{
						if (isspace(*p)) {
							*p = 0;
							break;
						}
					}

					if ( strncmp(".KERBEROS.OPTION.",lineBuf,17) ) {
 						CSendDlgItemMessage(hDialog, IDC_COMBO_REALM, CB_ADDSTRING, 0, (LPARAM)lineBuf);
						realm_count++;
					}
				}

				fclose(file);
			}
		}
		if (realm_count == 0)
			CSendDlgItemMessage(hDialog, IDC_COMBO_REALM, CB_ADDSTRING, 0, (LPARAM)realm);

		/* Select the default Realm */
		if (!realm[0] && hKrb5) {
			krb5_context ctx=0;
			char * def = 0;
			pkrb5_init_context(&ctx);
			pkrb5_get_default_realm(ctx,&def);
			if (def) {
				lstrcpy(realm, def);
				free(def);
			}
			pkrb5_free_context(ctx);
		}
		CSetDlgItemText(hDialog, IDC_COMBO_REALM, realm);

		/* Set Lifetime Slider 
		 *   min value = 5
		 *   max value = 1440
		 *   current value 
		 */

		SetupSlider( hDialog, 
					 IDC_SLIDER_LIFETIME,
					 IDC_STATIC_LIFETIME_VALUE,
					 Leash_get_default_life_min(), 
					 Leash_get_default_life_max(), 
					 lifetime );

		/* Set Forwardable checkbox */
		CheckDlgButton(hDialog, IDC_CHECK_FORWARDABLE, forwardable);
		/* Set NoAddress checkbox */
		CheckDlgButton(hDialog, IDC_CHECK_NOADDRESS, noaddresses);
        if ( disable_noaddresses )
            EnableWindow(GetDlgItem(hDialog,IDC_CHECK_NOADDRESS),FALSE);
		/* Set Renewable checkbox */
		CheckDlgButton(hDialog, IDC_CHECK_RENEWABLE, renew_till);
		/* if not renewable, disable Renew Till slider */
		/* if renewable, set Renew Till slider 
		 *     min value
		 *     max value
		 *     current value
		 */
		SetupSlider( hDialog, 
					 IDC_SLIDER_RENEWLIFE, 
					 IDC_STATIC_RENEW_TILL_VALUE,
					 Leash_get_default_renew_min(), 
					 Leash_get_default_renew_max(),
					 renew_till);
		if (renew_till) {
			EnableWindow(GetDlgItem(hDialog,IDC_SLIDER_RENEWLIFE),TRUE);
		} else {
			EnableWindow(GetDlgItem(hDialog,IDC_SLIDER_RENEWLIFE),FALSE);
		}

        // Compute sizes of items necessary to show/hide the advanced options
        GetWindowRect( hDialog, &dlgRect );
        {
            RECT okRect, staticRect;
            GetWindowRect(GetDlgItem(hDialog,IDC_STATIC_LIFETIME),&staticRect);
            GetWindowRect(GetDlgItem(hDialog,IDOK),&okRect);
            hideDiff = okRect.top - staticRect.top;
        }

        if ( hKrb5 ) {
            if (Leash_get_hide_kinit_options())
                AdjustOptions(hDialog,0,hideDiff);
        } else {
            AdjustOptions(hDialog,0,hideDiff);
            EnableWindow(GetDlgItem(hDialog,IDC_BUTTON_OPTIONS),FALSE);
            ShowWindow(GetDlgItem(hDialog,IDC_BUTTON_OPTIONS),SW_HIDE);
        }

        /* setup text of stuff. */

        if (Position.x > 0 && Position.y > 0 &&
            Position.x < GetSystemMetrics(SM_CXSCREEN) &&
            Position.y < GetSystemMetrics(SM_CYSCREEN))
            SetWindowPos(hDialog, HWND_TOP, Position.x, Position.y, 0, 0, SWP_NOSIZE);
        else /* Center the window on the desktop */
            SetWindowPos(hDialog, HWND_TOP, 
                         (GetSystemMetrics(SM_CXSCREEN) - dlgRect.right + dlgRect.left)/2, 
                         (GetSystemMetrics(SM_CYSCREEN) - dlgRect.bottom + dlgRect.top)/2, 
                         0, 0,
                         SWP_NOSIZE);

        /* Take keyboard focus */
        SetActiveWindow(hDialog);
        SetForegroundWindow(hDialog);
        if (GetDlgCtrlID((HWND) wParam) != IDC_EDIT_PRINCIPAL) 
        { 
            SetFocus(GetDlgItem(hDialog, IDC_EDIT_PRINCIPAL));
        } 
        break;

	case WM_HSCROLL:
		switch (LOWORD(wParam)) {
		case TB_THUMBTRACK:
		case TB_THUMBPOSITION: 
			{
				long pos = HIWORD(wParam); // the position of the slider
				int  ctrlID = GetDlgCtrlID((HWND)lParam);

				if (ctrlID == IDC_SLIDER_RENEWLIFE) {
					SetWindowText(GetDlgItem(hDialog, IDC_STATIC_RENEW_TILL_VALUE),
								   NewSliderString(IDC_SLIDER_RENEWLIFE,pos));
				}
				if (ctrlID == IDC_SLIDER_LIFETIME) {
					SetWindowText(GetDlgItem(hDialog, IDC_STATIC_LIFETIME_VALUE),
								   NewSliderString(IDC_SLIDER_LIFETIME,pos));
				}
			}
			break;
        case TB_BOTTOM:
        case TB_TOP:
        case TB_ENDTRACK:
        case TB_LINEDOWN:
        case TB_LINEUP:
        case TB_PAGEDOWN:
        case TB_PAGEUP:
		default:
			{
				int  ctrlID = GetDlgCtrlID((HWND)lParam);
				long pos = SendMessage(GetDlgItem(hDialog,ctrlID), TBM_GETPOS, 0, 0); // the position of the slider

				if (ctrlID == IDC_SLIDER_RENEWLIFE) {
					SetWindowText(GetDlgItem(hDialog, IDC_STATIC_RENEW_TILL_VALUE),
								   NewSliderString(IDC_SLIDER_RENEWLIFE,pos));
				}
				if (ctrlID == IDC_SLIDER_LIFETIME) {
					SetWindowText(GetDlgItem(hDialog, IDC_STATIC_LIFETIME_VALUE),
								   NewSliderString(IDC_SLIDER_LIFETIME,pos));
				}
			}
		}
        break;

    case WM_COMMAND:
        switch (wParam) {
		case IDC_BUTTON_OPTIONS:
			{
                AdjustOptions(hDialog,Leash_get_hide_kinit_options(),hideDiff);
                GetWindowRect(hDialog,&dlgRect);
                if ( dlgRect.bottom > GetSystemMetrics(SM_CYSCREEN))
                    SetWindowPos( hDialog,0,
                                  dlgRect.left,
                                  GetSystemMetrics(SM_CYSCREEN) - dlgRect.bottom + dlgRect.top,
                                  0,0,
                                  SWP_NOZORDER|SWP_NOSIZE);

			}
			break;
		case IDC_CHECK_RENEWABLE:
			{
				if (IsDlgButtonChecked(hDialog, IDC_CHECK_RENEWABLE)) {
					EnableWindow(hSliderRenew,TRUE);
				} else {
					EnableWindow(hSliderRenew,FALSE);
				}
			}
			break;
        case ID_HELP:
			{	
				WinHelp(GetWindow(hDialog,GW_OWNER), KRB_HelpFile, HELP_CONTEXT,
						ID_INITTICKETS);
			}
			break;
        case ID_CLOSEME:
			{
				CleanupSliders();
				memset(password,0,sizeof(password));
				RemoveProp(hDialog, "HANDLES_HELP");
				EndDialog(hDialog, (int)lParam);
                return TRUE;
			}
			break;
        case IDOK:
			{
				DWORD value = 0;

				CGetDlgItemText(hDialog, IDC_EDIT_PRINCIPAL, username, sizeof(username));
				CGetDlgItemText(hDialog, IDC_EDIT_PASSWORD, password, sizeof(password));
				CGetDlgItemText(hDialog, IDC_COMBO_REALM, realm, sizeof(realm));

				if (!username[0])
				{
					MessageBox(hDialog, 
                                "You are not allowed to enter a blank username.",
								"Invalid Principal",
								MB_OK | MB_ICONSTOP);
					return TRUE;
				}
				if (!realm[0])
				{
					MessageBox(hDialog, 
                                "You are not allowed to enter a blank realm.",
								"Invalid Principal",
								MB_OK | MB_ICONSTOP);
					return TRUE;
				}

				if (Leash_get_default_uppercaserealm())
				{
					// found
					strupr(realm);
				}
				
				if (!password[0])
				{
					MessageBox(hDialog, 
                                "You are not allowed to enter a blank password.",
								"Invalid Password",
								MB_OK | MB_ICONSTOP);
					return TRUE;
				}
				
				lifetime = NewSliderValue(hDialog, IDC_SLIDER_LIFETIME);

				forwardable = IsDlgButtonChecked(hDialog, IDC_CHECK_FORWARDABLE);
				noaddresses = IsDlgButtonChecked(hDialog, IDC_CHECK_NOADDRESS);
				if (IsDlgButtonChecked(hDialog, IDC_CHECK_RENEWABLE)) {
					renew_till = NewSliderValue(hDialog, IDC_SLIDER_RENEWLIFE);
				} else {
					 renew_till= 0;
				}

				sprintf(principal,"%s@%s",username,realm);
				lsh_errno = Leash_int_kinit_ex( 0,
											   hDialog,
											   principal, password, lifetime,
											   forwardable,
											   proxiable,
											   renew_till,
											   noaddresses,
											   publicip,
                                               1
											   );
				if (lsh_errno != 0)
				{
					int capslock;
					LONG check_time;
					char *cp;

					err_context = "";
					switch(lsh_errno)
					{
					case LSH_INVPRINCIPAL:
					case LSH_INVINSTANCE:
                    case KRBERR(KDC_PR_UNKNOWN):
                        CSendDlgItemMessage(hDialog, IDC_EDIT_PRINCIPAL, EM_SETSEL, 0, 256);
                        SetFocus(GetDlgItem(hDialog,IDC_EDIT_PRINCIPAL));
                        break;
					case LSH_INVREALM:
                        CSendDlgItemMessage(hDialog, IDC_COMBO_REALM, EM_SETSEL, 0, 256);
                        SetFocus(GetDlgItem(hDialog,IDC_COMBO_REALM));
						break;
					case KRBERR(RD_AP_TIME):
					case KRBERR(KDC_SERVICE_EXP):
						check_time = Leash_timesync(1);
						if( check_time == 0 ){
							SendMessage(hDialog, WM_COMMAND, IDOK, 0);
							return(TRUE);
						} else {
							lsh_errno = check_time;
							return(TRUE);
						}
						break;
                    default:
                        CSendDlgItemMessage(hDialog, IDC_EDIT_PASSWORD, EM_SETSEL, 0, 256);
                        SetFocus(GetDlgItem(hDialog,IDC_EDIT_PASSWORD));
						return(TRUE);
					}
#ifdef COMMENT
					capslock = lsh_getkeystate(VK_CAPITAL);
					/* low-order bit means caps lock is
					toggled; if so, warn user since there's
					been an error. */
					if (capslock & 1)
					{
						lstrcpy((LPSTR)gbuf, (LPSTR)err_context);
						cp = gbuf + lstrlen((LPSTR)gbuf);
						if (cp != gbuf)
							*cp++ = ' ';
						lstrcpy(cp, "(This may be because your CAPS LOCK key is down.)");
						err_context = gbuf;
					}

					// XXX		    DoNiftyErrorReport(lsh_errno, ISCHPASSWD ? ""
					// XXX				       : "Ticket initialization failed.");
#endif /* COMMENT */
					return TRUE;
				}

                if ( Leash_get_default_preserve_kinit_settings() ) 
                {
                    Leash_set_default_lifetime(lifetime);
                    if ( renew_till > 0 ) {
                        Leash_set_default_renew_till(renew_till);
                        Leash_set_default_renewable(1);
                    } else {
                        Leash_set_default_renewable(0);
                    }
                    Leash_set_default_forwardable(forwardable);
                    Leash_set_default_noaddresses(noaddresses);
                }

                if ( lpdi->size >= sizeof(LSH_DLGINFO_EX) ) {
                    strncpy(lpdi->out.username, username, LEASH_USERNAME_SZ);
                    lpdi->out.username[LEASH_USERNAME_SZ-1] = 0;
                    strncpy(lpdi->out.realm, realm, LEASH_REALM_SZ);
                    lpdi->out.realm[LEASH_REALM_SZ-1] = 0;
                }
				
                CloseMe(TRUE); /* success */
                return FALSE;
			}
			break;
        case IDCANCEL:
            CloseMe(FALSE);
            break;
        }
        break;

    case WM_MOVE:
#ifdef _WIN32
#define LONG2POINT(l,pt) ((pt).x=(SHORT)LOWORD(l),  \
						   (pt).y=(SHORT)HIWORD(l))
	        LONG2POINT(lParam,Position);
#else
			Position = MAKEPOINT(lParam);
#endif
        break;
    }
    return FALSE;
}

/* Callback function for the Change Password Dialog box */

INT_PTR
CALLBACK
NewPasswordProc(
    HWND hDialog,
    UINT message,
    WPARAM wParam,
    LPARAM lParam
    )
{
    static POINT Position = { -1, -1 };
    static char username[LEASH_USERNAME_SZ]="";
	static char realm[LEASH_REALM_SZ]="";
	static char password[256]="";
	static char password2[256]="";
	static char password3[256]="";
    static LPLSH_DLGINFO_EX lpdi;
	static HWND hDlg=0;
    char gbuf[256];                 /* global buffer for random stuff. */
	char principal[256];
	long realm_count = 0;

    switch (message) {

    case WM_INITDIALOG:
		hDlg = hDialog;

        SetVersionInfo(hDialog,IDC_STATIC_VERSION,IDC_STATIC_COPYRIGHT);

        *( (LPLSH_DLGINFO_EX far *)(&lpdi) ) = (LPLSH_DLGINFO_EX)(LPSTR)lParam;

		if ((lpdi->size < sizeof(LSH_DLGINFO_EX) && 
             lpdi->size != LSH_DLGINFO_EX_V1_SZ) ||
			 lpdi->dlgtype != DLGTYPE_CHPASSWD) {

			MessageBox(hDialog, "An incorrect initialization data structure was provided.",
						"PasswordProc()",
						MB_OK | MB_ICONSTOP);
			return FALSE;
		}

        if ( lpdi->size >= sizeof(LSH_DLGINFO_EX) ) {
            lpdi->out.username[0] = 0;
            lpdi->out.realm[0] = 0;
        }

        SetWindowText(hDialog, lpdi->title);

        SetProp(hDialog, "HANDLES_HELP", (HANDLE)1);

        if (lpdi->username)
            lstrcpy(username, lpdi->username);
		if (lpdi->realm)
			lstrcpy(realm, lpdi->realm);

        CSetDlgItemText(hDialog, IDC_EDIT_PRINCIPAL, username);
        CSetDlgItemText(hDialog, IDC_EDIT_PASSWORD, "");
        CSetDlgItemText(hDialog, IDC_EDIT_PASSWORD2, "");
        CSetDlgItemText(hDialog, IDC_EDIT_PASSWORD3, "");

#if 0  /* 20030619 - mjv wishes to return to the default character */
		/* echo spaces */
		CSendDlgItemMessage(hDialog, IDC_EDIT_PASSWORD, EM_SETPASSWORDCHAR, 32, 0);
		CSendDlgItemMessage(hDialog, IDC_EDIT_PASSWORD2, EM_SETPASSWORDCHAR, 32, 0);
		CSendDlgItemMessage(hDialog, IDC_EDIT_PASSWORD3, EM_SETPASSWORDCHAR, 32, 0);
#endif

		/* Populate list of Realms */
		CSendDlgItemMessage(hDialog, IDC_COMBO_REALM, CB_RESETCONTENT, 0, 0);
		CSendDlgItemMessage(hDialog, IDC_COMBO_REALM, CB_LIMITTEXT, 192, 0);

		if (pprofile_get_subsection_names && pprofile_free_list) {
			const char*  rootSection[] = {"realms", NULL};
			const char** rootsec = rootSection;
			char **sections = NULL, **cpp = NULL, *value = NULL;

			char krb5_conf[MAX_PATH+1];

			if (!GetProfileFile(krb5_conf,sizeof(krb5_conf))) {
				profile_t profile;
				long retval;
				const char *filenames[2];

				filenames[0] = krb5_conf;
				filenames[1] = NULL;
				retval = pprofile_init(filenames, &profile);
				if (!retval) {
					retval = pprofile_get_subsection_names(profile,	rootsec, &sections);

					if (!retval)
					{
						for (cpp = sections; *cpp; cpp++)
						{
							CSendDlgItemMessage(hDialog, IDC_COMBO_REALM, CB_ADDSTRING, 0, (LPARAM)*cpp);
							realm_count++;
						}
					}
					pprofile_free_list(sections);
					pprofile_release(profile);
				}
			}
		} else {
			FILE * file;
			char krb_conf[MAX_PATH+1];
			char * p;

			if (!GetKrb4ConFile(krb_conf,sizeof(krb_conf)) && 
				(file = fopen(krb_conf, "rt")))
			{
				char lineBuf[256];
				// Skip the default realm
				readstring(file,lineBuf,sizeof(lineBuf));

				// Read the defined realms
				while (TRUE)
				{
					if (readstring(file,lineBuf,sizeof(lineBuf)) < 0)
						break;

					if (*(lineBuf + strlen(lineBuf) - 1) == '\r')
						*(lineBuf + strlen(lineBuf) - 1) = 0;

					for (p=lineBuf; *p ; p++)
					{
						if (isspace(*p)) {
							*p = 0;
							break;
						}
					}

					if ( strncmp(".KERBEROS.OPTION.",lineBuf,17) ) {
 						CSendDlgItemMessage(hDialog, IDC_COMBO_REALM, CB_ADDSTRING, 0, (LPARAM)lineBuf);
						realm_count++;
					}
				}

				fclose(file);
			}
		}
		if (realm_count == 0)
			CSendDlgItemMessage(hDialog, IDC_COMBO_REALM, CB_ADDSTRING, 0, (LPARAM)realm);

		/* Select the default Realm */
		if (!realm[0] && hKrb5) {
			krb5_context ctx=0;
			char * def = 0;
			pkrb5_init_context(&ctx);
			pkrb5_get_default_realm(ctx,&def);
			if (def) {
				lstrcpy(realm, def);
				free(def);
			}
			pkrb5_free_context(ctx);
		}
		CSetDlgItemText(hDialog, IDC_COMBO_REALM, realm);

        /* setup text of stuff. */

        if (Position.x > 0 && Position.y > 0 &&
            Position.x < GetSystemMetrics(SM_CXSCREEN) &&
            Position.y < GetSystemMetrics(SM_CYSCREEN))
            SetWindowPos(hDialog, 0, Position.x, Position.y, 0, 0, 
                         SWP_NOSIZE | SWP_NOZORDER);
        else { /* Center the window on the desktop */
            RECT dlgRect;
            GetWindowRect( hDialog, &dlgRect );
            SetWindowPos(hDialog, 0, 
                         (GetSystemMetrics(SM_CXSCREEN) - dlgRect.right + dlgRect.left)/2, 
                         (GetSystemMetrics(SM_CYSCREEN) - dlgRect.bottom + dlgRect.top)/2, 
                         0, 0,
                         SWP_NOSIZE | SWP_NOZORDER);
        }
        /* set window pos to last saved window pos */
        break;

    case WM_COMMAND:
        switch (wParam) {
        case ID_HELP:
			{	
				WinHelp(GetWindow(hDialog,GW_OWNER), KRB_HelpFile, HELP_CONTEXT,
						ID_INITTICKETS);
			}
			break;
        case ID_CLOSEME:
			{
				CleanupSliders();
				memset(password,0,sizeof(password));
				memset(password2,0,sizeof(password2));
				memset(password3,0,sizeof(password3));
				RemoveProp(hDialog, "HANDLES_HELP");
				EndDialog(hDialog, (int)lParam);
                return TRUE;
			}
			break;
        case IDOK:
			{
				DWORD value = 0;
				int i = 0;
                int bit8 = 0;

				CGetDlgItemText(hDialog, IDC_EDIT_PRINCIPAL, username, sizeof(username));
				CGetDlgItemText(hDialog, IDC_EDIT_PASSWORD, password, sizeof(password));
				CGetDlgItemText(hDialog, IDC_EDIT_PASSWORD2, password2, sizeof(password2));
				CGetDlgItemText(hDialog, IDC_EDIT_PASSWORD3, password3, sizeof(password3));
				CGetDlgItemText(hDialog, IDC_COMBO_REALM, realm, sizeof(realm));

				if (!username[0])
				{
					MessageBox(hDialog, "You are not allowed to enter a "
								"blank username.",
								"Invalid Principal",
								MB_OK | MB_ICONSTOP);
					return TRUE;
				}
				if (!realm[0])
				{
					MessageBox(hDialog, "You are not allowed to enter a "
								"blank realm.",
								"Invalid Principal",
								MB_OK | MB_ICONSTOP);
					return TRUE;
				}

				if (Leash_get_default_uppercaserealm())
				{
					// found
					strupr(realm);
				}
				
				if (!password[0] || !password2[0] || !password3[0])
				{
					MessageBox(hDialog, "You are not allowed to enter a "
								"blank password.",
								"Invalid Password",
								MB_OK | MB_ICONSTOP);
					return TRUE;
				}

				for( i = 0; i < 255; i++ ){
                    if( password2[i] == '\0' ){
                        if ( bit8 ) {
                            MessageBox(hDialog, 
                                        "Passwords should not contain non-ASCII characters.",
                                        "Internationalization Warning",
                                        MB_OK | MB_ICONINFORMATION);
                        }
                        i = 255;
                        break;
                    } else if( !isprint(password2[i]) ){
                        memset(password2, '\0', sizeof(password2));
                        memset(password3, '\0', sizeof(password3));
                        /* I claim these passwords in the name of planet '\0'... */
                        MessageBox(hDialog, 
                                   "Passwords may not contain non-printable characters.",
                                    "Invalid Password",
                                    MB_OK | MB_ICONSTOP);
                        return TRUE;
                    } else if ( password2[i] > 127 )
                        bit8 = 1;
				}

				if (lstrcmp(password2, password3))
				{
                    MessageBox(hDialog, 
                                "The new password was not entered the same way twice.",
                                "Password validation error",
                                MB_OK | MB_ICONSTOP);
                    return TRUE;
				}

				sprintf(principal,"%s@%s",username,realm);

                lsh_errno = Leash_int_changepwd(principal, password, password2, 0, 1);
				if (lsh_errno != 0)
				{
					int capslock;
					LONG check_time;
					char *cp;

					err_context = "";
					switch(lsh_errno)
					{
					case LSH_INVPRINCIPAL:
					case LSH_INVINSTANCE:
					case LSH_INVREALM:
					case KRBERR(KDC_PR_UNKNOWN):
						break;
					case KRBERR(RD_AP_TIME):
					case KRBERR(KDC_SERVICE_EXP):
						check_time = Leash_timesync(1);
						if( check_time == 0 ){
							SendMessage(hDialog, WM_COMMAND, IDOK, 0);
							return(TRUE);
						} else {
							lsh_errno = check_time;
							return(TRUE);
						}
						break;
					default:
						return(TRUE);
					}
#ifdef COMMENT
					capslock = lsh_getkeystate(VK_CAPITAL);
					/* low-order bit means caps lock is
					toggled; if so, warn user since there's
					been an error. */
					if (capslock & 1)
					{
						lstrcpy((LPSTR)gbuf, (LPSTR)err_context);
						cp = gbuf + lstrlen((LPSTR)gbuf);
						if (cp != gbuf)
							*cp++ = ' ';
						lstrcpy(cp, "(This may be because your CAPS LOCK key is down.)");
						err_context = gbuf;
					}

					// XXX		    DoNiftyErrorReport(lsh_errno, ISCHPASSWD ? ""
					// XXX				       : "Ticket initialization failed.");
#endif /* COMMENT */              
                    return TRUE;
				}

                if ( lpdi->size >= sizeof(LSH_DLGINFO_EX) ) {
                    strncpy(lpdi->out.username, username, LEASH_USERNAME_SZ);
                    lpdi->out.username[LEASH_USERNAME_SZ-1] = 0;
                    strncpy(lpdi->out.realm, realm, LEASH_REALM_SZ);
                    lpdi->out.realm[LEASH_REALM_SZ-1] = 0;
                }

                CloseMe(TRUE); /* success */
			}
			break;
        case IDCANCEL:
            CloseMe(FALSE);
            break;
        }
        break;

    case WM_MOVE:
#ifdef _WIN32
#define LONG2POINT(l,pt) ((pt).x=(SHORT)LOWORD(l),  \
						   (pt).y=(SHORT)HIWORD(l))
	        LONG2POINT(lParam,Position);
#else
			Position = MAKEPOINT(lParam);
#endif
        break;
    }
    return FALSE;
}

