--- /dev/null
+/*
+ * cns.c
+ *
+ * Tabs 4
+ *
+ * Main routine of the Kerberos user interface. Also handles
+ * all dialog level management functions.
+ *
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ */
+
+#if !defined(KRB5) && !defined(KRB4)
+ #define KRB5 1
+#endif
+
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <malloc.h>
+#include <ctype.h>
+#include <time.h>
+
+#ifdef KRB4
+ #define DEFINE_SOCKADDR
+ #include "mit-copyright.h"
+ #include "krb.h"
+ #include "kadm.h"
+ #include "org.h"
+#endif
+
+#ifdef KRB5
+ #define NEED_SOCKETS
+ #include "krb5.h"
+ #include "krbini.h"
+ #include "com_err.h"
+
+ #define DEFAULT_TKT_LIFE 120
+ #define ANAME_SZ 40
+ #define REALM_SZ 40
+ #define SNAME_SZ 40
+ #define INST_SZ 40
+ #define MAX_KPW_LEN 128
+ /* include space for '.' and '@' */
+ #define MAX_K_NAME_SZ (ANAME_SZ + INST_SZ + REALM_SZ + 2)
+ #define ORGANIZATION "Cygnus Support"
+
+ #define CREDENTIALS char
+#endif
+
+#include "cns.h"
+#include "tktlist.h"
+
+/*
+ * Constants
+ */
+#define BLOCK_MAX_SEC 30 /* Blocking timeout duration */
+#define KWIN_UPDATE_PERIOD 30000 /* Every 30 seconds update the screen */
+#define TIME_BUFFER 300 /* Pop-up time buffer in seconds */
+#define WM_KWIN_SETNAME (WM_USER+100) /* Sets the name fields in the dialog */
+
+enum { /* Actions after login */
+ LOGIN_AND_EXIT,
+ LOGIN_AND_MINIMIZE,
+ LOGIN_AND_RUN,
+};
+
+/*
+ * Globals
+ */
+static HICON kwin_icons[MAX_ICONS]; /* Icons depicting time */
+static HFONT hfontdialog = NULL; /* Font in which the dialog is drawn. */
+static HFONT hfonticon = NULL; /* Font for icon label */
+static HINSTANCE hinstance;
+static int dlgncmdshow; /* ncmdshow from WinMain */
+static char confname[FILENAME_MAX]; /* current krb.conf location */
+static char realmsname[FILENAME_MAX]; /* current krb.realms location */
+static UINT wm_kerberos_changed; /* Registered message for cache changing */
+static int action; /* After login actions */
+static UINT kwin_timer_id; /* Timer being used for update */
+static BOOL alert; /* Actions on ticket expiration */
+static BOOL beep;
+static BOOL alerted; /* TRUE when user already alerted */
+static BOOL isblocking = FALSE; /* TRUE when blocked in WinSock */
+static DWORD blocking_end_time; /* Ending tick count for blocking timeout */
+static FARPROC hook_instance; /* Intance handle for blocking hook function */
+
+#ifdef KRB5
+ krb5_context k5_context;
+ krb5_ccache k5_ccache;
+#endif
+
+/*+
+ * Function: Called during blocking operations. Implement a timeout
+ * if nothing occurs within the specified time, cancel the blocking
+ * operation. Also permit the user to press escape in order to
+ * cancel the blocking operation.
+ *
+ * Returns: TRUE if we got and dispatched a message, FALSE otherwise.
+ */
+BOOL __export CALLBACK
+blocking_hook_proc (void)
+{
+ MSG msg;
+ BOOL rc;
+
+ if (GetTickCount() > blocking_end_time) {
+ WSACancelBlockingCall();
+ return FALSE;
+ }
+
+ rc = (BOOL) PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
+ if (!rc)
+ return FALSE;
+
+ if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE) {
+ WSACancelBlockingCall();
+ blocking_end_time = msg.time - 1;
+ return FALSE;
+ }
+
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+
+ return TRUE;
+
+} /* blocking_hook_proc */
+
+
+/*+
+ * Function: Set up a blocking hook function.
+ *
+ * Parameters:
+ * timeout - # of seconds to block for before cancelling.
+ */
+static void
+start_blocking_hook (
+ int timeout)
+{
+ FARPROC proc;
+
+ if (isblocking)
+ return;
+
+ isblocking = TRUE;
+ blocking_end_time = GetTickCount() + (1000 * timeout);
+ hook_instance = MakeProcInstance(blocking_hook_proc, hinstance);
+ proc = WSASetBlockingHook(hook_instance);
+ assert(proc != NULL);
+
+} /* start_blocking_hook */
+
+
+/*+
+ * Function: End the blocking hook fuction set up above.
+ */
+static void
+end_blocking_hook (void)
+{
+
+ FreeProcInstance(hook_instance);
+ WSAUnhookBlockingHook();
+ isblocking = FALSE;
+
+} /* end_blocking_hook */
+
+
+/*+
+ * Function: Centers the specified window on the screen.
+ *
+ * Parameters:
+ * hwnd - the window to center on the screen.
+ */
+static void
+center_dialog (
+ HWND hwnd)
+{
+ int scrwidth, scrheight;
+ int dlgwidth, dlgheight;
+ RECT r;
+ HDC hdc;
+
+ if (hwnd == NULL)
+ return;
+
+ GetWindowRect(hwnd, &r);
+ dlgwidth = r.right - r.left;
+ dlgheight = r.bottom - r.top ;
+ hdc = GetDC(NULL);
+ scrwidth = GetDeviceCaps(hdc, HORZRES);
+ scrheight = GetDeviceCaps(hdc, VERTRES);
+ ReleaseDC(NULL, hdc);
+ r.left = (scrwidth - dlgwidth) / 2;
+ r.top = (scrheight - dlgheight) / 2;
+ MoveWindow(hwnd, r.left, r.top, dlgwidth, dlgheight, TRUE);
+
+} /* center_dialog */
+
+
+/*+
+ * Function: Positions the kwin dialog either to the saved location
+ * or the center of the screen if no saved location.
+ *
+ * Parameters:
+ * hwnd - the window to center on the screen.
+ */
+static void
+position_dialog (
+ HWND hwnd)
+{
+ int n;
+ int scrwidth, scrheight;
+ HDC hdc;
+ char position[256];
+ int x, y, cx, cy;
+
+ if (hwnd == NULL)
+ return;
+
+ hdc = GetDC(NULL);
+ scrwidth = GetDeviceCaps(hdc, HORZRES);
+ scrheight = GetDeviceCaps(hdc, VERTRES);
+ ReleaseDC(NULL, hdc);
+ GetPrivateProfileString(INI_DEFAULTS, INI_POSITION, "",
+ position, sizeof(position), KERBEROS_INI);
+
+ n = sscanf(position, " [%d , %d , %d , %d", &x, &y, &cx, &cy);
+ if (n != 4 ||
+ x > scrwidth ||
+ y > scrheight ||
+ x + cx < 0 ||
+ y + cy < 0)
+ center_dialog(hwnd);
+ else
+ MoveWindow(hwnd, x, y, cx, cy, TRUE);
+
+} /* position_dialog */
+
+
+/*+
+ * Function: Set font of all dialog items.
+ *
+ * Parameters:
+ * hwnd - the dialog to set the font of
+ */
+static void
+set_dialog_font (
+ HWND hwnd,
+ HFONT hfont)
+{
+ hwnd = GetWindow(hwnd, GW_CHILD);
+
+ while (hwnd != NULL) {
+ SendMessage(hwnd, WM_SETFONT, (WPARAM) hfont, 0);
+ hwnd = GetWindow(hwnd, GW_HWNDNEXT);
+ }
+
+} /* set_dialog_font */
+
+
+/*+
+ * Function: Trim leading and trailing white space from a string.
+ *
+ * Parameters:
+ * s - the string to trim.
+ */
+void
+trim (
+ char *s)
+{
+ int l;
+ int i;
+
+ for (i = 0; s[i]; i++)
+ if (s[i] != ' ' && s[i] != '\t')
+ break;
+
+ l = strlen(&s[i]);
+ memmove(s, &s[i], l + 1);
+
+ for (l--; l >= 0; l--) {
+ if (s[l] != ' ' && s[l] != '\t')
+ break;
+ }
+ s[l + 1] = 0;
+
+} /* trim */
+
+
+/*+
+ * Function: This routine figures out the current time epoch and
+ * returns the conversion factor. It exists because Microloss
+ * screwed the pooch on the time() and _ftime() calls in its release
+ * 7.0 libraries. They changed the epoch to Dec 31, 1899!
+ */
+time_t
+kwin_get_epoch (void)
+{
+ static struct tm jan_1_70 = {0, 0, 0, 1, 0, 70};
+ time_t epoch = 0;
+
+ epoch = -mktime(&jan_1_70); /* Seconds til 1970 localtime */
+ epoch += _timezone; /* Seconds til 1970 GMT */
+
+ return epoch;
+
+} /* kwin_get_epoch */
+
+
+/*+
+ * Function: Save the credentials for later restoration.
+ *
+ * Parameters:
+ * c - Returned pointer to saved credential cache.
+ *
+ * pname - Returned as principal name of session.
+ *
+ * pinstance - Returned as principal instance of session.
+ *
+ * ncred - Returned number of credentials saved.
+ */
+static void
+push_credentials (
+ CREDENTIALS **cp,
+ char *pname,
+ char *pinstance,
+ int *ncred)
+{
+#ifdef KRB4
+ int i;
+ char service[ANAME_SZ];
+ char instance[INST_SZ];
+ char realm[REALM_SZ];
+ CREDENTIALS *c;
+
+ if (krb_get_tf_fullname ((char *) 0, pname, pinstance, (char *) 0) != KSUCCESS) {
+ pname[0] = 0;
+
+ pinstance[0] = 0;
+ }
+
+ *ncred = krb_get_num_cred();
+ if (*ncred <= 0)
+ return;
+
+ c= malloc(*ncred * sizeof(CREDENTIALS));
+ assert(c != NULL);
+ if (c == NULL) {
+ *ncred = 0;
+
+ return;
+ }
+
+ for (i = 0; i < *ncred; i++) {
+ krb_get_nth_cred(service, instance, realm, i + 1);
+ krb_get_cred(service, instance, realm, &c[i]);
+ }
+
+ *cp = c;
+#endif
+
+#ifdef KRB5 /* FIXME */
+ return;
+#endif
+
+} /* push_credentials */
+
+
+/*+
+ * Function: Restore the saved credentials.
+ *
+ * c - Pointer to saved credential cache.
+ *
+ * pname - Principal name of session.
+ *
+ * pinstance - Principal instance of session.
+ *
+ * ncred - Number of credentials saved.
+ */
+static void
+pop_credentials (
+ CREDENTIALS *c,
+ char *pname,
+ char *pinstance,
+ int ncred)
+{
+#ifdef KRB4
+ int i;
+
+ if (pname[0])
+ in_tkt(pname, pinstance);
+ else
+ dest_tkt();
+
+ if (ncred <= 0)
+ return;
+
+ for (i = 0; i < ncred; i++) {
+ krb_save_credentials(c[i].service, c[i].instance, c[i].realm,
+ c[i].session, c[i].lifetime, c[i].kvno, &(c[i].ticket_st),
+ c[i].issue_date);
+ }
+
+ free(c);
+#endif
+#ifdef KRB5 /* FIXME */
+ return;
+#endif
+
+} /* pop_credentials */
+
+
+/*+
+ * Function: Changes the password.
+ *
+ * Parameters:
+ * hwnd - the current window from which command was invoked.
+ *
+ * name - name of user to change password for
+ *
+ * instance - instance of user to change password for
+ *
+ * realm - realm in which to change password
+ *
+ * oldpw - the old password
+ *
+ * newpw - the new password to change to
+ *
+ * Returns: TRUE if change took place, FALSE otherwise.
+ */
+static BOOL
+change_password (
+ HWND hwnd,
+ char *name,
+ char *instance,
+ char *realm,
+ char *oldpw,
+ char *newpw)
+{
+#ifdef KRB4
+ des_cblock new_key;
+ char *ret_st;
+ int krc;
+ char *p;
+ CREDENTIALS *c;
+ int ncred;
+ char pname[ANAME_SZ];
+ char pinstance[INST_SZ];
+
+ push_credentials(&c, pname, pinstance, &ncred);
+ krc = krb_get_pw_in_tkt(
+ name, instance, realm, PWSERV_NAME, KADM_SINST, 1, oldpw);
+
+ if (krc != KSUCCESS) {
+ if (krc == INTK_BADPW)
+ p = "Old password is incorrect";
+ else
+ p = krb_get_err_text(krc);
+ pop_credentials(c, pname, pinstance, ncred);
+ MessageBox(hwnd, p, "", MB_OK | MB_ICONEXCLAMATION);
+
+ return FALSE;
+ }
+
+ krc = kadm_init_link(PWSERV_NAME, KRB_MASTER, realm);
+
+ if (krc != KSUCCESS) {
+ pop_credentials(c, pname, pinstance, ncred);
+ MessageBox(hwnd, kadm_get_err_text(krc), "", MB_OK | MB_ICONEXCLAMATION);
+
+ return FALSE;
+ }
+
+ des_string_to_key(newpw, new_key);
+ krc = kadm_change_pw2(new_key, newpw, &ret_st);
+ pop_credentials(c, pname, pinstance, ncred);
+
+ if (ret_st != NULL)
+ free(ret_st);
+
+ if (krc != KSUCCESS) {
+ MessageBox(hwnd, kadm_get_err_text(krc), "", MB_OK | MB_ICONEXCLAMATION);
+
+ return FALSE;
+ }
+
+ return TRUE;
+#endif
+
+#ifdef KRB5 /* FIXME */
+ MessageBox (NULL, "Changing passwords is not yet implemented", "", MB_ICONEXCLAMATION);
+ return TRUE;
+#endif
+
+} /* change_password */
+
+/*+
+ * Function: Process WM_COMMAND messages for the password dialog.
+ *
+ * Parameters:
+ * hwnd - the window recieving the message.
+ *
+ * wparam - id of the command item
+ *
+ * lparam - LOWORD=hwnd of control, HIWORD=notification message.
+ *
+ * Returns: TRUE if initialized sucessfully, false otherwise.
+ */
+static LONG
+password_command (
+ HWND hwnd,
+ WPARAM wparam,
+ LPARAM lparam)
+{
+ char name[ANAME_SZ];
+ char instance[INST_SZ];
+ char realm[REALM_SZ];
+ char oldpw[MAX_KPW_LEN];
+ char newpw1[MAX_KPW_LEN];
+ char newpw2[MAX_KPW_LEN];
+ HCURSOR hcursor;
+ BOOL b;
+ int id;
+
+ if (HIWORD(lparam) != BN_CLICKED) {
+ GetDlgItemText(hwnd, IDD_PASSWORD_NAME, name, sizeof(name));
+ trim(name);
+ GetDlgItemText(hwnd, IDD_PASSWORD_REALM, realm, sizeof(realm));
+ trim(realm);
+ GetDlgItemText(hwnd, IDD_OLD_PASSWORD, oldpw, sizeof(oldpw));
+ GetDlgItemText(hwnd, IDD_NEW_PASSWORD1, newpw1, sizeof(newpw1));
+ GetDlgItemText(hwnd, IDD_NEW_PASSWORD2, newpw2, sizeof(newpw2));
+ b = strlen(name) && strlen(realm) && strlen(oldpw) &&
+ strlen(newpw1) && strlen(newpw2);
+ EnableWindow(GetDlgItem(hwnd, IDOK), b);
+ id = (b) ? IDOK : IDD_PASSWORD_CR;
+ SendMessage(hwnd, DM_SETDEFID, id, 0);
+
+ return FALSE;
+ }
+
+ switch (wparam) {
+ case IDOK:
+ if (isblocking)
+ return TRUE;
+
+ GetDlgItemText(hwnd, IDD_PASSWORD_NAME, name, sizeof(name));
+ trim(name);
+ GetDlgItemText(hwnd, IDD_PASSWORD_INSTANCE, instance, sizeof(instance));
+ trim(instance);
+ GetDlgItemText(hwnd, IDD_PASSWORD_REALM, realm, sizeof(realm));
+ trim(realm);
+ GetDlgItemText(hwnd, IDD_OLD_PASSWORD, oldpw, sizeof(oldpw));
+ GetDlgItemText(hwnd, IDD_NEW_PASSWORD1, newpw1, sizeof(newpw1));
+ GetDlgItemText(hwnd, IDD_NEW_PASSWORD2, newpw2, sizeof(newpw2));
+
+ if (strcmp(newpw1, newpw2) != 0) {
+ MessageBox(hwnd, "The two passwords you entered don't match!", "",
+ MB_OK | MB_ICONEXCLAMATION);
+ SetDlgItemText(hwnd, IDD_NEW_PASSWORD1, "");
+ SetDlgItemText(hwnd, IDD_NEW_PASSWORD2, "");
+ PostMessage(hwnd, WM_NEXTDLGCTL,
+ GetDlgItem(hwnd, IDD_NEW_PASSWORD1), MAKELONG(1, 0));
+
+ return TRUE;
+ }
+
+ hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
+ start_blocking_hook(BLOCK_MAX_SEC);
+
+ if (change_password(hwnd, name, instance, realm, oldpw, newpw1))
+ EndDialog(hwnd, IDOK);
+ else
+ PostMessage(hwnd, WM_NEXTDLGCTL,
+ GetDlgItem(hwnd, IDD_OLD_PASSWORD), MAKELONG(1, 0));
+
+ end_blocking_hook();
+ SetCursor(hcursor);
+
+ return TRUE;
+
+ case IDCANCEL:
+ if (isblocking)
+ WSACancelBlockingCall();
+ EndDialog(hwnd, IDCANCEL);
+
+ return TRUE;
+
+ case IDD_PASSWORD_CR:
+ id = GetDlgCtrlID(GetFocus());
+ assert(id != 0);
+
+ if (id == IDD_NEW_PASSWORD2)
+ PostMessage(hwnd, WM_NEXTDLGCTL,
+ GetDlgItem(hwnd, IDD_PASSWORD_NAME), MAKELONG(1, 0));
+ else
+ PostMessage(hwnd, WM_NEXTDLGCTL, 0, 0);
+
+ return TRUE;
+
+ }
+
+ return FALSE;
+
+} /* password_command */
+
+
+/*+
+ * Function: Process WM_INITDIALOG messages for the password dialog.
+ * Set up all initial dialog values from the parent dialog.
+ *
+ * Parameters:
+ * hwnd - the window recieving the message.
+ *
+ * wparam - handle of the control for focus.
+ *
+ * lparam - lparam from dialog box call.
+ *
+ * Returns: TRUE if we didn't set the focus here,
+ * FALSE if we did.
+ */
+static BOOL
+password_initdialog (
+ HWND hwnd,
+ WPARAM wparam,
+ LPARAM lparam)
+{
+ char name[ANAME_SZ];
+ char instance[INST_SZ];
+ char realm[REALM_SZ];
+ HWND hwndparent;
+ int id;
+
+ center_dialog(hwnd);
+ set_dialog_font(hwnd, hfontdialog);
+
+ hwndparent = GetParent(hwnd);
+ assert(hwndparent != NULL);
+
+ GetDlgItemText(hwndparent, IDD_LOGIN_NAME, name, sizeof(name));
+ trim(name);
+ SetDlgItemText(hwnd, IDD_PASSWORD_NAME, name);
+
+ GetDlgItemText(hwndparent, IDD_LOGIN_INSTANCE, instance, sizeof(instance));
+ trim(instance);
+ SetDlgItemText(hwnd, IDD_PASSWORD_INSTANCE, instance);
+
+ GetDlgItemText(hwndparent, IDD_LOGIN_REALM, realm, sizeof(realm));
+ trim(realm);
+ SetDlgItemText(hwnd, IDD_PASSWORD_REALM, realm);
+
+ if (strlen(name) == 0)
+ id = IDD_PASSWORD_NAME;
+ else if (strlen(realm) == 0)
+ id = IDD_PASSWORD_REALM;
+ else
+ id = IDD_OLD_PASSWORD;
+
+ SetFocus(GetDlgItem(hwnd, id));
+
+ return FALSE;
+
+} /* password_initdialog */
+
+
+/*+
+ * Function: Process dialog specific messages for the password dialog.
+ *
+ * Parameters:
+ * hwnd - the dialog receiving the message.
+ *
+ * message - the message to process.
+ *
+ * wparam - wparam of the message.
+ *
+ * lparam - lparam of the message.
+ *
+ * Returns: TRUE if message handled locally, FALSE otherwise.
+ */
+static BOOL CALLBACK
+password_dlg_proc (
+ HWND hwnd,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam)
+{
+ LRESULT rc;
+
+ switch (message) {
+
+ case WM_INITDIALOG:
+ return password_initdialog(hwnd, wparam, lparam);
+
+ case WM_COMMAND:
+ password_command(hwnd, wparam, lparam);
+ return (BOOL) rc;
+
+ case WM_SETCURSOR:
+ if (isblocking) {
+ SetCursor(LoadCursor(NULL, IDC_WAIT));
+ SetWindowLong(hwnd, DWL_MSGRESULT, TRUE);
+
+ return TRUE;
+ }
+ break;
+ }
+
+ return FALSE;
+
+} /* password_dlg_proc */
+
+
+/*+
+ * Function: Display and process the password dialog.
+ *
+ * Parameters:
+ * hwnd - the parent window for the dialog
+ *
+ * Returns: TRUE if the dialog completed successfully, FALSE otherwise.
+ */
+static BOOL
+password_dialog (
+ HWND hwnd)
+{
+ DLGPROC dlgproc;
+ int rc;
+
+ dlgproc = (FARPROC) MakeProcInstance(password_dlg_proc, hinstance);
+ assert(dlgproc != NULL);
+
+ if (dlgproc == NULL)
+ return FALSE;
+
+ rc = DialogBox(hinstance, MAKEINTRESOURCE(ID_PASSWORD), hwnd, dlgproc);
+ assert(rc != -1);
+
+ FreeProcInstance((FARPROC) dlgproc);
+
+ return rc == IDOK;
+
+} /* password_dialog */
+
+
+/*+
+ * Function: Process WM_INITDIALOG messages for the options dialog.
+ * Set up all initial dialog values from the KERBEROS_INI file.
+ *
+ * Parameters:
+ * hwnd - the window recieving the message.
+ *
+ * wparam - handle of the control for focus.
+ *
+ * lparam - lparam from dialog box call.
+ *
+ * Returns: TRUE if we didn't set the focus here,
+ * FALSE if we did.
+ */
+static LONG
+opts_initdialog (
+ HWND hwnd,
+ WPARAM wparam,
+ LPARAM lparam)
+{
+ char defname[FILENAME_MAX];
+ UINT rc;
+ int lifetime;
+
+ center_dialog(hwnd);
+ set_dialog_font(hwnd, hfontdialog);
+
+ /* krb.conf file */
+ rc = GetWindowsDirectory(defname, sizeof(defname));
+ assert(rc > 0);
+
+ strcat(defname, "\\");
+ strcat(defname, DEF_KRB_CONF);
+ GetPrivateProfileString(INI_FILES, INI_KRB_CONF, defname,
+ confname, sizeof(confname), KERBEROS_INI);
+ _strupr(confname);
+ SetDlgItemText(hwnd, IDD_CONF, confname);
+
+ /* krb.realms file */
+ rc = GetWindowsDirectory(defname, sizeof(defname));
+ assert(rc > 0);
+
+ strcat(defname, "\\");
+ strcat(defname, DEF_KRB_REALMS);
+ GetPrivateProfileString(INI_FILES, INI_KRB_REALMS, defname,
+ realmsname, sizeof(realmsname), KERBEROS_INI);
+ _strupr(realmsname);
+ SetDlgItemText(hwnd, IDD_REALMS, realmsname);
+
+ /* Ticket duration */
+ lifetime = GetPrivateProfileInt(INI_OPTIONS, INI_DURATION,
+ DEFAULT_TKT_LIFE * 5, KERBEROS_INI);
+ SetDlgItemInt(hwnd, IDD_LIFETIME, lifetime, FALSE);
+
+ /* Expiration action */
+ GetPrivateProfileString(INI_EXPIRATION, INI_ALERT, "No",
+ defname, sizeof(defname), KERBEROS_INI);
+ alert = _stricmp(defname, "Yes") == 0;
+ SendDlgItemMessage(hwnd, IDD_ALERT, BM_SETCHECK, alert, 0);
+ GetPrivateProfileString(INI_EXPIRATION, INI_BEEP, "No",
+ defname, sizeof(defname), KERBEROS_INI);
+ beep = _stricmp(defname, "Yes") == 0;
+ SendDlgItemMessage(hwnd, IDD_BEEP, BM_SETCHECK, beep, 0);
+
+ return TRUE;
+
+} /* opts_initdialog */
+
+
+/*+
+ * Function: Process WM_COMMAND messages for the options dialog.
+ *
+ * Parameters:
+ * hwnd - the window recieving the message.
+ *
+ * wparam - id of the command item
+ *
+ * lparam - LOWORD=hwnd of control, HIWORD=notification message.
+ *
+ * Returns: TRUE if initialized sucessfully, false otherwise.
+ */
+static LONG
+opts_command (
+ HWND hwnd,
+ WPARAM wparam,
+ LPARAM lparam)
+{
+ char defname[FILENAME_MAX];
+ char *p;
+ BOOL b;
+ int lifetime;
+ int rc;
+
+ switch (wparam) {
+
+ case IDOK:
+ /* Ticket duration */
+ lifetime = GetDlgItemInt(hwnd, IDD_LIFETIME, &b, FALSE);
+
+ if (!b) {
+ MessageBox(hwnd, "Lifetime must be a number!", "", MB_OK | MB_ICONEXCLAMATION);
+
+ return TRUE;
+ }
+
+ _itoa(lifetime, defname, 10);
+ b = WritePrivateProfileString(INI_OPTIONS, INI_DURATION, defname, KERBEROS_INI);
+ assert(b);
+
+ /* krb.conf file */
+ GetDlgItemText(hwnd, IDD_CONF, confname, sizeof(confname));
+ trim(confname);
+ rc = GetWindowsDirectory(defname, sizeof(defname));
+ assert(rc > 0);
+
+ strcat(defname, "\\");
+ strcat(defname, DEF_KRB_CONF);
+ if (_stricmp(confname, defname) == 0 || !defname[0])
+ p = NULL;
+ else
+ p = confname;
+ b = WritePrivateProfileString(INI_FILES, INI_KRB_CONF, p, KERBEROS_INI);
+ assert(b);
+
+ /* krb.realms file */
+ GetDlgItemText(hwnd, IDD_REALMS, realmsname, sizeof(realmsname));
+ trim(realmsname);
+ rc = GetWindowsDirectory(defname, sizeof(defname));
+ assert(rc > 0);
+
+ strcat(defname, "\\");
+ strcat(defname, DEF_KRB_REALMS);
+ if (_stricmp(realmsname, defname) == 0 || !defname[0])
+ p = NULL;
+ else
+ p = defname;
+ b = WritePrivateProfileString(INI_FILES, INI_KRB_REALMS, p, KERBEROS_INI);
+ assert(b);
+
+ /* Expiration action */
+ alert = (BOOL) SendDlgItemMessage(hwnd, IDD_ALERT, BM_GETCHECK, 0, 0);
+ p = (alert) ? "Yes" : "No";
+ b = WritePrivateProfileString(INI_EXPIRATION, INI_ALERT, p, KERBEROS_INI);
+ assert(b);
+
+ beep = (BOOL) SendDlgItemMessage(hwnd, IDD_BEEP, BM_GETCHECK, 0, 0);
+ p = (beep) ? "Yes" : "No";
+ b = WritePrivateProfileString(INI_EXPIRATION, INI_BEEP, p, KERBEROS_INI);
+ assert(b);
+
+ EndDialog(hwnd, IDOK);
+
+ return TRUE;
+
+ case IDCANCEL:
+ EndDialog(hwnd, IDCANCEL);
+
+ return TRUE;
+ }
+
+ return FALSE;
+
+} /* opts_command */
+
+
+/*+
+ * Function: Process dialog specific messages for the opts dialog.
+ *
+ * Parameters:
+ * hwnd - the dialog receiving the message.
+ *
+ * message - the message to process.
+ *
+ * wparam - wparam of the message.
+ *
+ * lparam - lparam of the message.
+ *
+ * Returns: TRUE if message handled locally, FALSE otherwise.
+ */
+static BOOL CALLBACK
+opts_dlg_proc (
+ HWND hwnd,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam)
+{
+ LRESULT rc;
+
+ switch (message) {
+
+ case WM_INITDIALOG:
+ rc = opts_initdialog(hwnd, wparam, lparam);
+
+ return (BOOL) rc;
+
+ case WM_COMMAND:
+ rc = opts_command(hwnd, wparam, lparam);
+
+ return (BOOL) rc;
+ }
+
+ return FALSE;
+
+} /* opts_dlg_proc */
+
+
+/*+
+ * Function: Display and process the options dialog.
+ *
+ * Parameters:
+ * hwnd - the parent window for the dialog
+ *
+ * Returns: TRUE if the dialog completed successfully, FALSE otherwise.
+ */
+static BOOL
+opts_dialog (
+ HWND hwnd)
+{
+ DLGPROC dlgproc;
+ int rc;
+
+ dlgproc = (FARPROC) MakeProcInstance(opts_dlg_proc, hinstance);
+ assert(dlgproc != NULL);
+
+ if (dlgproc == NULL)
+ return FALSE;
+
+ rc = DialogBox(hinstance, MAKEINTRESOURCE(ID_OPTS), hwnd, dlgproc);
+ assert(rc != -1);
+
+ FreeProcInstance((FARPROC) dlgproc);
+
+ return rc == IDOK;
+
+} /* opts_dialog */
+
+
+/*+
+ * Function: Save most recent login triplets for placement on the
+ * bottom of the file menu.
+ *
+ * Parameters:
+ * hwnd - the handle of the window containing the menu to edit.
+ *
+ * name - A login name to save in the recent login list
+ *
+ * instance - An instance to save in the recent login list
+ *
+ * realm - A realm to save in the recent login list
+ */
+static void
+kwin_push_login (
+ HWND hwnd,
+ char *name,
+ char *instance,
+ char *realm)
+{
+ HMENU hmenu;
+ int i;
+ int id;
+ int ctitems;
+ char fullname[MAX_K_NAME_SZ + 3];
+ char menuitem[MAX_K_NAME_SZ + 3];
+ BOOL rc;
+
+ strcpy(fullname, "&x ");
+ strcat(fullname, name);
+ strcat(fullname, ".");
+ strcat(fullname, instance);
+ strcat(fullname, "@");
+ strcat(fullname, realm);
+
+ hmenu = GetMenu(hwnd);
+ assert(hmenu != NULL);
+
+ hmenu = GetSubMenu(hmenu, 0);
+ assert(hmenu != NULL);
+
+ ctitems = GetMenuItemCount(hmenu);
+ assert(ctitems >= FILE_MENU_ITEMS);
+
+ if (ctitems == FILE_MENU_ITEMS) {
+ rc = AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
+ assert(rc);
+
+ ctitems++;
+ }
+
+ for (i = FILE_MENU_ITEMS + 1; i < ctitems; i++) {
+ GetMenuString(hmenu, i, menuitem, sizeof(menuitem), MF_BYPOSITION);
+
+ if (strcmp(&fullname[3], &menuitem[3]) == 0) {
+ rc = RemoveMenu(hmenu, i, MF_BYPOSITION);
+ assert(rc);
+
+ ctitems--;
+
+ break;
+ }
+ }
+
+ rc = InsertMenu(hmenu, FILE_MENU_ITEMS + 1, MF_BYPOSITION, 1, fullname);
+ assert(rc);
+
+ ctitems++;
+ if (ctitems - FILE_MENU_ITEMS - 1 > FILE_MENU_MAX_LOGINS) {
+ RemoveMenu(hmenu, ctitems - 1, MF_BYPOSITION);
+
+ ctitems--;
+ }
+
+ id = 0;
+ for (i = FILE_MENU_ITEMS + 1; i < ctitems; i++) {
+ GetMenuString(hmenu, i, menuitem, sizeof(menuitem), MF_BYPOSITION);
+
+ rc = RemoveMenu(hmenu, i, MF_BYPOSITION);
+ assert(rc);
+
+ menuitem[1] = '1' + id;
+ rc = InsertMenu(hmenu, i, MF_BYPOSITION, IDM_FIRST_LOGIN + id, menuitem);
+ assert(rc);
+
+ id++;
+ }
+
+} /* kwin_push_login */
+
+
+/*+
+ * Function: Initialize the logins on the file menu form the KERBEROS.INI
+ * file.
+ *
+ * Parameters:
+ * hwnd - handle of the dialog containing the file menu.
+ */
+static void
+kwin_init_file_menu (
+ HWND hwnd)
+{
+ HMENU hmenu;
+ int i;
+ char login[sizeof(INI_LOGIN)+1];
+ char menuitem[MAX_K_NAME_SZ + 3];
+ int id;
+ BOOL rc;
+
+ hmenu = GetMenu(hwnd);
+ assert(hmenu != NULL);
+
+ hmenu = GetSubMenu(hmenu, 0);
+ assert(hmenu != NULL);
+
+ strcpy(login, INI_LOGIN);
+ id = 0;
+ for (i = 0; i < FILE_MENU_MAX_LOGINS; i++) {
+ login[sizeof(INI_LOGIN) - 1] = '1' + i;
+ login[sizeof(INI_LOGIN)] = 0;
+ GetPrivateProfileString(INI_RECENT_LOGINS, login, "",
+ &menuitem[3], sizeof(menuitem) - 3, KERBEROS_INI);
+ if (!menuitem[3])
+ continue;
+
+ menuitem[0] = '&';
+ menuitem[1] = '1' + id;
+ menuitem[2] = ' ';
+
+ if (id == 0) {
+ rc = AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
+ assert(rc);
+ }
+ AppendMenu(hmenu, MF_STRING, IDM_FIRST_LOGIN + id, menuitem);
+
+ id++;
+ }
+
+} /* kwin_init_file_menu */
+
+
+/*+
+ * Function: Save the items on the file menu in the KERBEROS.INI file.
+ *
+ * Parameters:
+ * hwnd - handle of the dialog containing the file menu.
+ */
+static void
+kwin_save_file_menu (
+ HWND hwnd)
+{
+ HMENU hmenu;
+ int i;
+ int id;
+ int ctitems;
+ char menuitem[MAX_K_NAME_SZ + 3];
+ char login[sizeof(INI_LOGIN)+1];
+ BOOL rc;
+
+ hmenu = GetMenu(hwnd);
+ assert(hmenu != NULL);
+
+ hmenu = GetSubMenu(hmenu, 0);
+ assert(hmenu != NULL);
+
+ strcpy(login, INI_LOGIN);
+ ctitems = GetMenuItemCount(hmenu);
+ assert(ctitems >= FILE_MENU_ITEMS);
+
+ id = 0;
+ for (i = FILE_MENU_ITEMS + 1; i < ctitems; i++) {
+ GetMenuString(hmenu, i, menuitem, sizeof(menuitem), MF_BYPOSITION);
+ login[sizeof(INI_LOGIN) - 1] = '1' + id;
+ login[sizeof(INI_LOGIN)] = 0;
+
+ rc = WritePrivateProfileString(INI_RECENT_LOGINS, login, &menuitem[3], KERBEROS_INI);
+ assert(rc);
+
+ id++;
+ }
+
+} /* kwin_save_file_menu */
+
+
+
+/*+
+ * Function: Given an expiration time, choose an appropriate
+ * icon to display.
+ *
+ * Parameters:
+ * expiration time of expiration in time() compatible units
+ *
+ * Returns: Handle of icon to display
+ */
+HICON
+kwin_get_icon (
+ time_t expiration)
+{
+ int ixicon;
+ time_t dt;
+
+ dt = expiration - time(NULL);
+ dt = dt / 60; /* convert to minutes */
+ if (dt <= 0)
+ ixicon = IDI_EXPIRED - IDI_FIRST_CLOCK;
+ else if (dt > 60)
+ ixicon = IDI_TICKET - IDI_FIRST_CLOCK;
+ else
+ ixicon = (int) (dt / 5);
+
+ return kwin_icons[ixicon];
+
+} /* kwin_get_icon */
+
+
+/*+
+ * Function: Intialize name fields in the Kerberos dialog.
+ *
+ * Parameters:
+ * hwnd - the window recieving the message.
+ *
+ * fullname - the full kerberos name to initialize with
+ */
+static void
+kwin_init_name (
+ HWND hwnd,
+ char *fullname)
+{
+ char name[ANAME_SZ];
+ char instance[INST_SZ];
+ char realm[REALM_SZ];
+ int krc;
+
+ if (fullname == NULL || fullname[0] == 0) {
+ #ifdef KRB4
+ strcpy(name, krb_get_default_user());
+ GetPrivateProfileString(INI_DEFAULTS, INI_INSTANCE, "",
+ instance, sizeof(instance), KERBEROS_INI);
+ krc = krb_get_lrealm(realm, 1);
+ if (krc != KSUCCESS)
+ realm[0] = 0;
+ #endif
+
+
+ #ifdef KRB5
+ {
+ krb5_error_code code;
+ char *ptr;
+
+ GetPrivateProfileString (INI_DEFAULTS, INI_USER, "",
+ name, sizeof(name), KERBEROS_INI);
+ //GetPrivateProfileString(INI_DEFAULTS, INI_INSTANCE, "",
+ // instance, sizeof(instance), KERBEROS_INI);
+ *instance = '\0';
+
+ *realm = '\0';
+ code = krb5_get_default_realm (k5_context, &ptr);
+ if (! code) {
+ strcpy (realm, ptr);
+ free (ptr);
+ }
+ }
+ #endif
+
+ GetPrivateProfileString(INI_DEFAULTS, INI_REALM, realm,
+ realm, sizeof(realm), KERBEROS_INI);
+ } else {
+ #ifdef KRB4
+ kname_parse(name, instance, realm, fullname);
+ #endif
+
+ #ifdef KRB5
+ krc = k5_kname_parse(name, realm, fullname);
+ *instance = '\0';
+ #endif
+ }
+
+ SetDlgItemText(hwnd, IDD_LOGIN_NAME, name);
+ name[0] = 0;
+ GetDlgItemText(hwnd, IDD_LOGIN_NAME, name, sizeof(name));
+ SetDlgItemText(hwnd, IDD_LOGIN_INSTANCE, instance);
+ SetDlgItemText(hwnd, IDD_LOGIN_REALM, realm);
+
+} /* kwin_init_name */
+
+
+/*+
+ * Function: Set the focus to the name control if no name
+ * exists, the realm control if no realm exists or the
+ * password control. Uses PostMessage not SetFocus.
+ *
+ * Parameters:
+ * hwnd - the Window handle of the parent.
+ */
+void
+kwin_set_default_focus (
+ HWND hwnd)
+{
+ char name[ANAME_SZ];
+ char realm[REALM_SZ];
+ HWND hwnditem;
+
+ GetDlgItemText(hwnd, IDD_LOGIN_NAME, name, sizeof(name));
+
+ trim(name);
+ if (strlen(name) <= 0)
+ hwnditem = GetDlgItem(hwnd, IDD_LOGIN_NAME);
+ else {
+ GetDlgItemText(hwnd, IDD_LOGIN_REALM, realm, sizeof(realm));
+ trim(realm);
+
+ if (strlen(realm) <= 0)
+ hwnditem = GetDlgItem(hwnd, IDD_LOGIN_REALM);
+ else
+ hwnditem = GetDlgItem(hwnd, IDD_LOGIN_PASSWORD);
+ }
+
+ PostMessage(hwnd, WM_NEXTDLGCTL, hwnditem, MAKELONG(1, 0));
+
+} /* kwin_set_default_focus */
+
+
+/*+
+ * Function: Save the values which live in the KERBEROS.INI file.
+ *
+ * Parameters:
+ * hwnd - the window handle of the dialog containing fields to
+ * be saved
+ */
+static void
+kwin_save_name (
+ HWND hwnd)
+{
+ char name[ANAME_SZ];
+ char instance[INST_SZ];
+ char realm[REALM_SZ];
+
+ GetDlgItemText(hwnd, IDD_LOGIN_NAME, name, sizeof(name));
+ trim(name);
+
+ #ifdef KRB4
+ krb_set_default_user(name);
+ GetDlgItemText(hwnd, IDD_LOGIN_INSTANCE, instance, sizeof(instance));
+ trim(instance);
+ WritePrivateProfileString(INI_DEFAULTS, INI_INSTANCE, instance, KERBEROS_INI);
+ #endif
+
+ #ifdef KRB5
+ WritePrivateProfileString(INI_DEFAULTS, INI_USER, name, KERBEROS_INI);
+ *instance = '\0';
+ #endif
+
+ GetDlgItemText(hwnd, IDD_LOGIN_REALM, realm, sizeof(realm));
+ trim(realm);
+ WritePrivateProfileString(INI_DEFAULTS, INI_REALM, realm, KERBEROS_INI);
+
+ kwin_push_login(hwnd, name, instance, realm);
+
+} /* kwin_save_name */
+
+
+/*+
+ * Function: Process WM_INITDIALOG messages. Set the fonts
+ * for all items on the dialog and populate the ticket list.
+ * Also set the default values for user, instance and realm.
+ *
+ * Parameters:
+ * hwnd - the window recieving the message.
+ *
+ * wparam - handle of the control for focus.
+ *
+ * lparam - lparam from dialog box call.
+ *
+ * Returns: TRUE if we didn't set the focus here,
+ * FALSE if we did.
+ */
+static BOOL
+kwin_initdialog (
+ HWND hwnd,
+ WPARAM wparam,
+ LPARAM lparam)
+{
+ LOGFONT lf;
+ HDC hdc;
+ char name[ANAME_SZ];
+
+ position_dialog(hwnd);
+ ticket_init_list(GetDlgItem(hwnd, IDD_TICKET_LIST));
+ kwin_init_file_menu(hwnd);
+ kwin_init_name(hwnd, (char *) lparam);
+ hdc = GetDC(NULL);
+ assert(hdc != NULL);
+
+ memset(&lf, 0, sizeof(lf));
+ lf.lfHeight = -MulDiv(9, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+ strcpy(lf.lfFaceName, "Arial");
+ hfontdialog = CreateFontIndirect(&lf);
+ assert(hfontdialog != NULL);
+
+ if (hfontdialog == NULL) {
+ ReleaseDC(NULL, hdc);
+
+ return TRUE;
+ }
+
+ lf.lfHeight = -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+ hfonticon = CreateFontIndirect(&lf);
+ assert(hfonticon != NULL);
+
+ if (hfonticon == NULL) {
+ ReleaseDC(NULL, hdc);
+
+ return TRUE;
+ }
+
+ ReleaseDC(NULL, hdc);
+
+ set_dialog_font(hwnd, hfontdialog);
+ GetDlgItemText(hwnd, IDD_LOGIN_NAME, name, sizeof(name));
+ trim(name);
+
+ if (strlen(name) > 0)
+ SetFocus(GetDlgItem(hwnd, IDD_LOGIN_PASSWORD));
+ else
+ SetFocus(GetDlgItem(hwnd, IDD_LOGIN_NAME));
+
+ ShowWindow(hwnd, dlgncmdshow);
+ kwin_timer_id = SetTimer(hwnd, 1, KWIN_UPDATE_PERIOD, NULL);
+ assert(kwin_timer_id != 0);
+
+ return FALSE;
+
+} /* kwin_initdialog */
+
+
+/*+
+ * Function: Process WM_DESTROY messages. Delete the font
+ * created for use by the controls.
+ *
+ * Parameters:
+ * hwnd - the window recieving the message.
+ *
+ * wparam - none
+ *
+ * lparam - none
+ *
+ * Returns: 0
+ */
+static LONG
+kwin_destroy (
+ HWND hwnd,
+ WPARAM wparam,
+ LPARAM lparam)
+{
+ char position[256];
+ RECT r;
+ BOOL b;
+
+ ticket_destroy(GetDlgItem(hwnd, IDD_TICKET_LIST));
+
+ if (hfontdialog != NULL)
+ DeleteObject(hfontdialog);
+
+ if (hfonticon != NULL)
+ DeleteObject(hfonticon);
+
+ kwin_save_file_menu(hwnd);
+ GetWindowRect(hwnd, &r);
+ sprintf(position, "[%d,%d,%d,%d]", r.left, r.top,
+ r.right - r.left, r.bottom - r.top);
+ b = WritePrivateProfileString(INI_DEFAULTS, INI_POSITION, position, KERBEROS_INI);
+ assert(b);
+
+ KillTimer(hwnd, kwin_timer_id);
+
+ return 0;
+
+} /* kwin_destroy */
+
+
+/*+
+ * Function: Retrievs item WindowRect in hwnd client
+ * coordiate system.
+ *
+ * Parameters:
+ * hwnditem - the item to retrieve
+ *
+ * item - dialog in which into which to translate
+ *
+ * r - rectangle returned
+ */
+static void
+windowrect (
+ HWND hwnditem,
+ HWND hwnd,
+ RECT *r)
+{
+ GetWindowRect(hwnditem, r);
+ ScreenToClient(hwnd, (LPPOINT) &(r->left));
+ ScreenToClient(hwnd, (LPPOINT) &(r->right));
+
+} /* windowrect */
+
+
+/*+
+ * Function: Process WM_SIZE messages. Resize the
+ * list and position the buttons attractively.
+ *
+ * Parameters:
+ * hwnd - the window receiving the message.
+ *
+ * wparam - type of resize occuring
+ *
+ * lparam - LOWORD=width of client area,
+ * HIWORD=height of client area.
+ *
+ * Returns: 0
+ */
+static LONG
+kwin_size (
+ HWND hwnd,
+ WPARAM wparam,
+ LPARAM lparam)
+{
+ #define listgap 8
+ RECT r;
+ RECT rdlg;
+ int hmargin, vmargin;
+ HWND hwnditem;
+ int cx, cy;
+ int cxdlg, cydlg;
+ int i;
+ int titlebottom;
+ int editbottom;
+ int listbottom;
+ int gap;
+ int left;
+ int titleleft[IDD_MAX_TITLE - IDD_MIN_TITLE + 1];
+
+ if (wparam == SIZE_MINIMIZED)
+ return 0;
+
+ GetClientRect(hwnd, &rdlg);
+ cxdlg = LOWORD(lparam);
+ cydlg = HIWORD(lparam);
+
+ /*
+ * The ticket list title
+ */
+ hwnditem = GetDlgItem(hwnd, IDD_TICKET_LIST_TITLE);
+
+ if (hwnditem == NULL)
+ return 0;
+
+ windowrect(hwnditem, hwnd, &r);
+ hmargin = r.left;
+ vmargin = r.top;
+ cx = cxdlg - 2 * hmargin;
+ cy = r.bottom - r.top;
+ MoveWindow(hwnditem, r.left, r.top, cx, cy, TRUE);
+
+ /*
+ * The buttons
+ */
+ cx = 0;
+
+ for (i = IDD_MIN_BUTTON; i <= IDD_MAX_BUTTON; i++) {
+ hwnditem = GetDlgItem(hwnd, i);
+ windowrect(hwnditem, hwnd, &r);
+ if (i == IDD_MIN_BUTTON)
+ hmargin = r.left;
+
+ cx += r.right - r.left;
+ }
+
+ gap = (cxdlg - 2 * hmargin - cx) / (IDD_MAX_BUTTON - IDD_MIN_BUTTON);
+ left = hmargin;
+ for (i = IDD_MIN_BUTTON; i <= IDD_MAX_BUTTON; i++) {
+ hwnditem = GetDlgItem(hwnd, i);
+ windowrect(hwnditem, hwnd, &r);
+ editbottom = -r.top;
+ cx = r.right - r.left;
+ cy = r.bottom - r.top;
+ r.top = rdlg.bottom - vmargin - cy;
+ MoveWindow(hwnditem, left, r.top, cx, cy, TRUE);
+
+ left += cx + gap;
+ }
+
+ /*
+ * Edit fields
+ */
+ editbottom += r.top;
+
+ cx = 0;
+ for (i = IDD_MIN_EDIT; i <= IDD_MAX_EDIT; i++) {
+ hwnditem = GetDlgItem(hwnd, i);
+ windowrect(hwnditem, hwnd, &r);
+
+ if (i == IDD_MIN_EDIT) {
+ gap = r.right;
+ hmargin = r.left;
+ editbottom += r.bottom;
+ titlebottom = -r.top;
+ }
+ if (i == IDD_MIN_EDIT + 1)
+ gap = r.left - gap;
+
+ cx += r.right - r.left;
+ }
+
+ cx = cxdlg - 2 * hmargin - (IDD_MAX_EDIT - IDD_MIN_EDIT) * gap;
+ cx = cx / (IDD_MAX_EDIT - IDD_MIN_EDIT + 1);
+ left = hmargin;
+
+ for (i = IDD_MIN_EDIT; i <= IDD_MAX_EDIT; i++) {
+ hwnditem = GetDlgItem(hwnd, i);
+ windowrect(hwnditem, hwnd, &r);
+ cy = r.bottom - r.top;
+ r.top = editbottom - cy;
+ MoveWindow(hwnditem, left, r.top, cx, cy, TRUE);
+ titleleft[i-IDD_MIN_EDIT] = left;
+
+ left += cx + gap;
+ }
+
+ /*
+ * Edit field titles
+ */
+ titlebottom += r.top;
+ windowrect(GetDlgItem(hwnd, IDD_MIN_TITLE), hwnd, &r);
+ titlebottom += r.bottom;
+ listbottom = -r.top;
+
+ for (i = IDD_MIN_TITLE; i <= IDD_MAX_TITLE; i++) {
+ hwnditem = GetDlgItem(hwnd, i);
+ windowrect(hwnditem, hwnd, &r);
+ cx = r.right - r.left;
+ cy = r.bottom - r.top;
+ r.top = titlebottom - cy;
+ MoveWindow(hwnditem, titleleft[i-IDD_MIN_TITLE], r.top, cx, cy, TRUE);
+ }
+
+ /*
+ * The list
+ */
+ listbottom = r.top - listgap;
+ hwnditem = GetDlgItem(hwnd, IDD_TICKET_LIST);
+ windowrect(hwnditem, hwnd, &r);
+ hmargin = r.left;
+ cx = cxdlg - 2 * hmargin;
+ cy = listbottom - r.top;
+ MoveWindow(hwnditem, r.left, r.top, cx, cy, TRUE);
+
+ return 0;
+
+} /* kwin_size */
+
+
+/*+
+ * Function: Process WM_GETMINMAXINFO messages
+ *
+ * Parameters:
+ * hwnd - the window recieving the message.
+ *
+ * wparam - none.
+ *
+ * lparam - LPMINMAXINFO
+ *
+ * Returns: 0
+ */
+static LONG
+kwin_getminmaxinfo (
+ HWND hwnd,
+ WPARAM wparam,
+ LPARAM lparam)
+{
+ MINMAXINFO *lpmmi;
+
+ lpmmi = (MINMAXINFO *) lparam;
+ lpmmi->ptMinTrackSize.x = (KWIN_MIN_WIDTH * LOWORD(GetDialogBaseUnits())) / 4;
+ lpmmi->ptMinTrackSize.y = (KWIN_MIN_HEIGHT * HIWORD(GetDialogBaseUnits())) / 8;
+
+ return 0;
+
+} /* kwin_getminmaxinfo */
+
+
+/*+
+ * Function: Process WM_TIMER messages
+ *
+ * Parameters:
+ * hwnd - the window recieving the message.
+ *
+ * wparam - the timer id.
+ *
+ * lparam - timer callback proceedure
+ *
+ * Returns: 0
+ */
+static LONG
+kwin_timer (
+ HWND hwnd,
+ WPARAM wparam,
+ LPARAM lparam)
+{
+ HWND hwndfocus;
+ time_t t;
+ time_t expiration;
+ BOOL expired;
+ #ifdef KRB4
+ CREDENTIALS c;
+ int ncred;
+ int i;
+ char service[ANAME_SZ];
+ char instance[INST_SZ];
+ char realm[REALM_SZ];
+ #endif
+ #ifdef KRB5
+ krb5_error_code code;
+ krb5_cc_cursor cursor;
+ krb5_creds cred;
+ int n;
+ char *s;
+ #endif
+
+ if (wparam != 1)
+ return DefDlgProc(hwnd, WM_TIMER, wparam, lparam);
+
+ expired = FALSE;
+ ticket_init_list(GetDlgItem(hwnd, IDD_TICKET_LIST));
+
+ if (alerted) {
+ if (IsIconic(hwnd))
+ InvalidateRect(hwnd, NULL, TRUE);
+
+ return 0;
+ }
+
+ #ifdef KRB4
+ ncred = krb_get_num_cred();
+ for (i = 1; i <= ncred; i++) {
+ krb_get_nth_cred(service, instance, realm, i);
+
+ if (_stricmp(service, "krbtgt") == 0) {
+ /* Warn if ticket will expire w/i TIME_BUFFER seconds */
+ krb_get_cred(service, instance, realm, &c);
+ expiration = c.issue_date + (long) c.lifetime * 5L * 60L;
+ t = TIME_BUFFER + time(NULL);
+
+ if (t >= expiration) {
+ expired = TRUE;
+ /* Don't alert because of stale tickets */
+ if (t >= expiration + KWIN_UPDATE_PERIOD / 1000) {
+ alerted = TRUE;
+
+ if (IsIconic(hwnd))
+ InvalidateRect(hwnd, NULL, TRUE);
+ return 0;
+ }
+ break;
+ }
+ }
+ }
+ #endif
+
+ #ifdef KRB5
+ code = krb5_cc_start_seq_get (k5_context, k5_ccache, &cursor);
+
+ while (code == 0) {
+ code = krb5_cc_next_cred(k5_context, k5_ccache, &cursor, &cred);
+ if (code)
+ break;
+ n = krb5_princ_component(k5_context, cred.server, 0)->length;
+ s = krb5_princ_component(k5_context, cred.server, 0)->data;
+ if (n != KRB5_TGS_NAME_SIZE)
+ continue;
+ if (memcmp (KRB5_TGS_NAME, s, KRB5_TGS_NAME_SIZE))
+ continue;
+
+ /* Warn if ticket will expire w/i TIME_BUFFER seconds */
+ expiration = cred.times.endtime;
+ t = TIME_BUFFER + time(NULL);
+
+ if (t >= expiration) {
+ expired = TRUE;
+ /* Don't alert because of stale tickets */
+ if (t >= expiration + KWIN_UPDATE_PERIOD / 1000) {
+ alerted = TRUE;
+
+ if (IsIconic(hwnd))
+ InvalidateRect(hwnd, NULL, TRUE);
+ return 0;
+ }
+ break;
+ }
+ }
+ krb5_cc_end_seq_get(k5_context, k5_ccache, &cursor);
+
+ #endif
+
+ if (!expired) {
+ if (IsIconic(hwnd))
+ InvalidateRect(hwnd, NULL, TRUE);
+
+ return 0;
+ }
+
+ alerted = TRUE;
+
+ if (beep)
+ MessageBeep(MB_ICONEXCLAMATION);
+
+ if (alert) {
+ if (IsIconic(hwnd)) {
+ hwndfocus = GetFocus();
+ ShowWindow(hwnd, SW_RESTORE);
+ SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
+ SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
+ SetFocus(hwndfocus);
+ }
+
+ SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
+ SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
+
+ return 0;
+ }
+
+ if (IsIconic(hwnd))
+ InvalidateRect(hwnd, NULL, TRUE);
+
+ return 0;
+
+} /* kwin_timer */
+
+
+/*+
+ * Function: Process WM_COMMAND messages
+ *
+ * Parameters:
+ * hwnd - the window recieving the message.
+ *
+ * wparam - id of the command item
+ *
+ * lparam - LOWORD=hwnd of control, HIWORD=notification message.
+ *
+ * Returns: TRUE if initialized sucessfully, false otherwise.
+ */
+static LONG
+kwin_command (
+ HWND hwnd,
+ WPARAM wparam,
+ LPARAM lparam)
+{
+ char name[ANAME_SZ];
+ char instance[INST_SZ];
+ char realm[REALM_SZ];
+ char password[MAX_KPW_LEN];
+ HCURSOR hcursor;
+ BOOL blogin;
+ HMENU hmenu;
+ char menuitem[MAX_K_NAME_SZ + 3];
+ char copyright[128];
+ #ifdef KRB4
+ int lifetime;
+ int krc;
+ #endif
+ #ifdef KRB5
+ long lifetime;
+ krb5_error_code code;
+ krb5_principal principal;
+ krb5_creds creds;
+ krb5_principal server;
+ krb5_timestamp now;
+ #endif
+
+ #ifdef KRB4
+ EnableWindow(GetDlgItem(hwnd, IDD_TICKET_DELETE), krb_get_num_cred() > 0);
+ #endif
+
+ #ifdef KRB5
+ EnableWindow(GetDlgItem(hwnd, IDD_TICKET_DELETE), k5_get_num_cred() > 0);
+ #endif
+
+ GetDlgItemText(hwnd, IDD_LOGIN_NAME, name, sizeof(name));
+ trim(name);
+ blogin = strlen(name) > 0;
+
+ if (blogin) {
+ GetDlgItemText(hwnd, IDD_LOGIN_REALM, realm, sizeof(realm));
+ trim(realm);
+ blogin = strlen(realm) > 0;
+ }
+
+ if (blogin) {
+ GetDlgItemText(hwnd, IDD_LOGIN_PASSWORD, password, sizeof(password));
+ blogin = strlen(password) > 0;
+ }
+
+ EnableWindow(GetDlgItem(hwnd, IDD_LOGIN), blogin);
+
+ if (HIWORD(lparam) != BN_CLICKED && HIWORD(lparam) != 0 && HIWORD(lparam) != 1)
+ return FALSE;
+
+ if (wparam >= IDM_FIRST_LOGIN && wparam < IDM_FIRST_LOGIN + FILE_MENU_MAX_LOGINS) {
+ hmenu = GetMenu(hwnd);
+ assert(hmenu != NULL);
+
+ hmenu = GetSubMenu(hmenu, 0);
+ assert(hmenu != NULL);
+
+ if (!GetMenuString(hmenu, wparam, menuitem, sizeof(menuitem), MF_BYCOMMAND))
+ return TRUE;
+
+ if (menuitem[0])
+ kwin_init_name(hwnd, &menuitem[3]);
+
+ return TRUE;
+ }
+
+ switch (wparam) {
+ case IDM_EXIT:
+ if (isblocking)
+ WSACancelBlockingCall();
+ WinHelp(hwnd, KERBEROS_HLP, HELP_QUIT, 0);
+ PostQuitMessage(0);
+
+ return TRUE;
+
+ case IDD_LOGIN:
+ if (isblocking)
+ return TRUE;
+
+ GetDlgItemText(hwnd, IDD_LOGIN_NAME, name, sizeof(name));
+ trim(name);
+ GetDlgItemText(hwnd, IDD_LOGIN_INSTANCE, instance, sizeof(instance));
+ trim(instance);
+ GetDlgItemText(hwnd, IDD_LOGIN_REALM, realm, sizeof(realm));
+ trim(realm);
+ GetDlgItemText(hwnd, IDD_LOGIN_PASSWORD, password, sizeof(password));
+ trim(password);
+
+ hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
+ lifetime = GetPrivateProfileInt(INI_OPTIONS, INI_DURATION,
+ DEFAULT_TKT_LIFE * 5, KERBEROS_INI);
+ start_blocking_hook(BLOCK_MAX_SEC);
+
+ #ifdef KRB4
+ lifetime = (lifetime + 4) / 5;
+ krc = krb_get_pw_in_tkt(name, instance, realm, "krbtgt", realm,
+ lifetime, password);
+ #endif
+
+ #ifdef KRB5
+ code = krb5_parse_name(k5_context, name, &principal);
+ code = krb5_cc_initialize(k5_context, k5_ccache, principal);
+ memset(&creds, 0, sizeof(creds));
+ creds.client = principal;
+
+ code = krb5_build_principal_ext(k5_context, &server,
+ krb5_princ_realm(k5_context, principal)->length,
+ krb5_princ_realm(k5_context, principal)->data,
+ KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
+ krb5_princ_realm(k5_context, principal)->length,
+ krb5_princ_realm(k5_context, principal)->data, 0);
+
+ creds.server = server;
+
+ //code = krb5_os_localaddr(&address);
+ code = krb5_timeofday(k5_context, &now);
+
+ creds.times.starttime = 0;
+ creds.times.endtime = now + 60L * lifetime;
+ creds.times.renew_till = 0;
+
+ code = krb5_get_in_tkt_with_password(k5_context, 0, NULL, NULL,
+ NULL, password, k5_ccache, &creds, 0);
+
+ krb5_free_principal(k5_context, server);
+ //krb5_free_addresses(k5_context, address);
+
+ #endif
+
+ end_blocking_hook();
+ SetCursor(hcursor);
+ kwin_set_default_focus(hwnd);
+
+ #ifdef KRB4
+ if (krc != KSUCCESS) {
+ MessageBox(hwnd, krb_get_err_text(krc), "",
+ MB_OK | MB_ICONEXCLAMATION);
+
+ return TRUE;
+ }
+ #endif
+
+ #ifdef KRB5
+ if (code) {
+ com_err (NULL, code, "while logging in");
+ return TRUE;
+ }
+ // ticket_init_list(GetDlgItem(hwnd, IDD_TICKET_LIST));
+
+ #endif
+
+ SetDlgItemText(hwnd, IDD_LOGIN_PASSWORD, "");
+ kwin_save_name(hwnd);
+ alerted = FALSE;
+
+ switch (action) {
+ case LOGIN_AND_EXIT:
+ SendMessage(hwnd, WM_COMMAND, IDM_EXIT, 0);
+ break;
+
+ case LOGIN_AND_MINIMIZE:
+ ShowWindow(hwnd, SW_MINIMIZE);
+ break;
+ }
+
+ return TRUE;
+
+ case IDD_TICKET_DELETE:
+ if (isblocking)
+ return TRUE;
+
+ #ifdef KRB4
+ krc = dest_tkt();
+ if (krc != KSUCCESS)
+ MessageBox(hwnd, krb_get_err_text(krc), "",
+ MB_OK | MB_ICONEXCLAMATION);
+ #endif
+
+ #ifdef KRB5
+ code = k5_dest_tkt ();
+ // ticket_init_list(GetDlgItem(hwnd, IDD_TICKET_LIST));
+ #endif
+
+ kwin_set_default_focus(hwnd);
+ alerted = FALSE;
+
+ return TRUE;
+
+ case IDD_CHANGE_PASSWORD:
+ if (isblocking)
+ return TRUE;
+ password_dialog(hwnd);
+ kwin_set_default_focus(hwnd);
+
+ return TRUE;
+
+ case IDM_OPTIONS:
+ if (isblocking)
+ return TRUE;
+ opts_dialog(hwnd);
+
+ return TRUE;
+
+ case IDM_HELP_INDEX:
+ WinHelp(hwnd, KERBEROS_HLP, HELP_INDEX, 0);
+
+ return TRUE;
+
+ case 1234:
+ ticket_init_list(GetDlgItem(hwnd, IDD_TICKET_LIST));
+
+ return TRUE;
+
+ case IDM_ABOUT:
+ if (isblocking)
+ return TRUE;
+
+ strcpy(copyright, " Kerberos for Windows\n");
+ strcat(copyright, "\n Version 1.00\n\n");
+ strcat(copyright, " For support, contact:\n");
+ strcat(copyright, ORGANIZATION);
+ strcat(copyright, " - (415) 903-1400");
+ MessageBox(hwnd, copyright, "Kerberos", MB_OK);
+
+ return TRUE;
+ }
+
+ return FALSE;
+
+} /* kwin_command */
+
+
+/*+
+ * Function: Process WM_SYSCOMMAND messages by setting
+ * the focus to the password or name on restore.
+ *
+ * Parameters:
+ * hwnd - the window recieving the message.
+ *
+ * wparam - the syscommand option.
+ *
+ * lparam -
+ *
+ * Returns: 0
+ */
+static LONG
+kwin_syscommand (
+ HWND hwnd,
+ WPARAM wparam,
+ LPARAM lparam)
+{
+ if ((wparam & 0xFFF0) == SC_RESTORE)
+ kwin_set_default_focus(hwnd);
+
+ if ((wparam & 0xFFF0) == SC_CLOSE) {
+ SendMessage(hwnd, WM_COMMAND, IDM_EXIT, 0);
+
+ return 0;
+ }
+
+ return DefDlgProc(hwnd, WM_SYSCOMMAND, wparam, lparam);
+
+} /* kwin_syscommand */
+
+
+/*+
+ * Function: Process WM_PAINT messages by displaying an
+ * informative icon when we are iconic.
+ *
+ * Parameters:
+ * hwnd - the window recieving the message.
+ *
+ * wparam - none
+ *
+ * lparam - none
+ *
+ * Returns: 0
+ */
+static LONG
+kwin_paint (
+ HWND hwnd,
+ WPARAM wparam,
+ LPARAM lparam)
+{
+ HDC hdc;
+ PAINTSTRUCT ps;
+ HICON hicon;
+ time_t expiration = 0;
+ time_t dt;
+ char buf[20];
+ RECT r;
+ #ifdef KRB4
+ int i;
+ int ncred;
+ char service[ANAME_SZ];
+ char instance[INST_SZ];
+ char realm[REALM_SZ];
+ CREDENTIALS c;
+ #endif
+ #ifdef KRB5
+ krb5_error_code code;
+ krb5_cc_cursor cursor;
+ krb5_creds c;
+ int n;
+ char *service;
+ #endif
+
+ if (!IsIconic(hwnd))
+ return DefDlgProc(hwnd, WM_PAINT, wparam, lparam);
+
+ #ifdef KRB4
+ ncred = krb_get_num_cred();
+
+ for (i = 1; i <= ncred; i++) {
+ krb_get_nth_cred(service, instance, realm, i);
+ krb_get_cred(service, instance, realm, &c);
+ if (_stricmp(c.service, "krbtgt") == 0) {
+ expiration = c.issue_date - kwin_get_epoch() + (long) c.lifetime * 5L * 60L;
+ break;
+ }
+ }
+ #endif
+
+ #ifdef KRB5
+ code = krb5_cc_start_seq_get (k5_context, k5_ccache, &cursor);
+
+ while (code == 0) {
+ code = krb5_cc_next_cred(k5_context, k5_ccache, &cursor, &c);
+ if (code)
+ break;
+ n = krb5_princ_component(k5_context, c.server, 0)->length;
+ service = krb5_princ_component(k5_context, c.server, 0)->data;
+ if (n != KRB5_TGS_NAME_SIZE)
+ continue;
+ if (memcmp (KRB5_TGS_NAME, service, KRB5_TGS_NAME_SIZE))
+ continue;
+ expiration = c.times.endtime;
+ break;
+
+ }
+ krb5_cc_end_seq_get(k5_context, k5_ccache, &cursor);
+ #endif
+
+ hdc = BeginPaint(hwnd, &ps);
+ GetClientRect(hwnd, &r);
+ DefWindowProc(hwnd, WM_ICONERASEBKGND, hdc, 0);
+
+ if (expiration == 0) {
+ strcpy(buf, KWIN_DIALOG_NAME);
+ hicon = LoadIcon(hinstance, MAKEINTRESOURCE(IDI_KWIN));
+ }
+ else {
+ hicon = kwin_get_icon(expiration);
+ dt = (expiration - time(NULL)) / 60;
+
+ if (dt <= 0)
+ sprintf(buf, "%s - %s", KWIN_DIALOG_NAME, "Expired");
+ else if (dt < 60) {
+ dt %= 60;
+ sprintf(buf, "%s - %ld min", KWIN_DIALOG_NAME, dt);
+ }
+ else {
+ dt /= 60;
+ sprintf(buf, "%s - %ld hr", KWIN_DIALOG_NAME, dt);
+ }
+
+ if (dt > 1)
+ strcat(buf, "s");
+ }
+
+ DrawIcon(hdc, r.left, r.top, hicon);
+ EndPaint(hwnd, &ps);
+ SetWindowText(hwnd, buf);
+
+ return 0;
+
+} /* kwin_paint */
+
+
+/*+
+ * Function: Window proceedure for the Kerberos control panel dialog.
+ *
+ * Parameters:
+ * hwnd - the window receiving the message.
+ *
+ * message - the message to process.
+ *
+ * wparam - wparam of the message.
+ *
+ * lparam - lparam of the message.
+ *
+ * Returns: message dependent value.
+ */
+LRESULT __export CALLBACK
+kwin_wnd_proc (
+ HWND hwnd,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam)
+{
+ LRESULT rc;
+ int n;
+
+ if (message == wm_kerberos_changed) { /* Message from the ccache */
+ n = ticket_init_list(GetDlgItem(hwnd, IDD_TICKET_LIST));
+ EnableWindow(GetDlgItem(hwnd, IDD_TICKET_DELETE), n > 0);
+
+ return 0;
+ }
+
+ switch (message) {
+ case WM_GETMINMAXINFO:
+ rc = kwin_getminmaxinfo(hwnd, wparam, lparam);
+ return rc;
+
+ case WM_DESTROY:
+ rc = kwin_destroy(hwnd, wparam, lparam);
+ return rc;
+
+ case WM_MEASUREITEM:
+ if (wparam == IDD_TICKET_LIST) {
+ rc = ticket_measureitem(hwnd, wparam, lparam);
+ return rc;
+ }
+ break;
+
+ case WM_DRAWITEM:
+ if (wparam == IDD_TICKET_LIST) {
+ rc = ticket_drawitem(hwnd, wparam, lparam);
+ return rc;
+ }
+ break;
+
+ case WM_SETCURSOR:
+ if (isblocking) {
+ SetCursor(LoadCursor(NULL, IDC_WAIT));
+ return TRUE;
+ }
+ break;
+
+ case WM_SIZE:
+ rc = kwin_size(hwnd, wparam, lparam);
+ return rc;
+
+ case WM_SYSCOMMAND:
+ rc = kwin_syscommand(hwnd, wparam, lparam);
+ return rc;
+
+ case WM_TIMER:
+ rc = kwin_timer(hwnd, wparam, lparam);
+ return 0;
+
+ case WM_PAINT:
+ rc = kwin_paint(hwnd, wparam, lparam);
+ return rc;
+
+ case WM_ERASEBKGND:
+ if (!IsIconic(hwnd))
+ break;
+ return 0;
+
+ case WM_KWIN_SETNAME:
+ kwin_init_name(hwnd, (char *) lparam);
+ }
+
+ return DefDlgProc(hwnd, message, wparam, lparam);
+
+} /* kwin_wnd_proc */
+
+
+/*+
+ * Function: Dialog procedure called by the dialog manager
+ * to process dialog specific messages.
+ *
+ * Parameters:
+ * hwnd - the dialog receiving the message.
+ *
+ * message - the message to process.
+ *
+ * wparam - wparam of the message.
+ *
+ * lparam - lparam of the message.
+ *
+ * Returns: TRUE if message handled locally, FALSE otherwise.
+ */
+static BOOL CALLBACK
+kwin_dlg_proc (
+ HWND hwnd,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam)
+{
+ LRESULT rc;
+
+ switch (message) {
+ case WM_INITDIALOG:
+ return kwin_initdialog(hwnd, wparam, lparam);
+
+ case WM_COMMAND:
+ rc = kwin_command(hwnd, wparam, lparam);
+ return TRUE;
+ }
+
+ return FALSE;
+
+} /* kwin_dlg_proc */
+
+
+/*+
+ * Function: Initialize the kwin dialog class.
+ *
+ * Parameters:
+ * hinstance - the instance to initialize
+ *
+ * Returns: TRUE if dialog class registration is sucessfully, false otherwise.
+ */
+static BOOL
+kwin_init (
+ HINSTANCE hinstance)
+{
+ WNDCLASS class;
+ ATOM rc;
+
+ class.style = CS_HREDRAW | CS_VREDRAW;
+ class.lpfnWndProc = (WNDPROC) kwin_wnd_proc;
+ class.cbClsExtra = 0;
+ class.cbWndExtra = DLGWINDOWEXTRA;
+ class.hInstance = hinstance;
+ class.hIcon = NULL;
+// LoadIcon(hinstance, MAKEINTRESOURCE(IDI_KWIN));
+ class.hCursor = NULL;
+ class.hbrBackground = NULL;
+ class.lpszMenuName = NULL;
+ class.lpszClassName = KWIN_DIALOG_CLASS;
+
+ rc = RegisterClass (&class);
+ assert(rc);
+
+ return rc;
+
+} /* kwin_init */
+
+
+/*+
+ * Function: Initialize the KWIN application. This routine should
+ * only be called if no previous instance of the application
+ * exists. Currently it only registers a class for the kwin
+ * dialog type.
+ *
+ * Parameters:
+ * hinstance - the instance to initialize
+ *
+ * Returns: TRUE if initialized sucessfully, false otherwise.
+ */
+static BOOL
+init_application (
+ HINSTANCE hinstance)
+{
+ BOOL rc;
+
+ #ifdef KRB4
+ wm_kerberos_changed = krb_get_notification_message();
+ #endif
+
+ #ifdef KRB5
+ wm_kerberos_changed = krb5_get_notification_message();
+ #endif
+
+ rc = kwin_init(hinstance);
+
+ return rc;
+
+} /* init_application */
+
+
+/*+
+ * Function: Quits the KWIN application. This routine should
+ * be called when the last application instance exits.
+ *
+ * Parameters:
+ * hinstance - the instance which is quitting.
+ *
+ * Returns: TRUE if initialized sucessfully, false otherwise.
+ */
+static BOOL
+quit_application (
+ HINSTANCE hinstance)
+{
+ return TRUE;
+} /* quit_application */
+
+
+/*+
+ * Function: Initialize the current instance of the KWIN application.
+ *
+ * Parameters:
+ * hinstance - the instance to initialize
+ *
+ * ncmdshow - show flag to indicate wheather to come up minimized
+ * or not.
+ *
+ * Returns: TRUE if initialized sucessfully, false otherwise.
+ */
+static BOOL
+init_instance (
+ HINSTANCE hinstance,
+ int ncmdshow)
+{
+ WORD versionrequested;
+ WSADATA wsadata;
+ int rc;
+ char buf[20];
+ int i;
+
+ versionrequested = 0x0101; /* We need version 1.1 */
+ rc = WSAStartup(versionrequested, &wsadata);
+ if (rc != 0) {
+ MessageBox(NULL, "Couldn't initialize Winsock library", "", MB_OK | MB_ICONSTOP);
+
+ return FALSE;
+ }
+
+ if (versionrequested != wsadata.wVersion) {
+ WSACleanup();
+ MessageBox(NULL, "Winsock version 1.1 not available", "", MB_OK | MB_ICONSTOP);
+
+ return FALSE;
+ }
+
+ /*
+ * Set up expiration action
+ */
+ GetPrivateProfileString(INI_EXPIRATION, INI_ALERT, "No",
+ buf, sizeof(buf), KERBEROS_INI);
+ alert = _stricmp(buf, "Yes") == 0;
+ GetPrivateProfileString(INI_EXPIRATION, INI_BEEP, "No",
+ buf, sizeof(buf), KERBEROS_INI);
+ beep = _stricmp(buf, "Yes") == 0;
+
+ /*
+ * Load clock icons
+ */
+ for (i = IDI_FIRST_CLOCK; i <= IDI_LAST_CLOCK; i++)
+ kwin_icons[i - IDI_FIRST_CLOCK] = LoadIcon(hinstance, MAKEINTRESOURCE(i));
+
+ #ifdef KRB4
+ krb_start_session(NULL);
+ #endif
+
+ #ifdef KRB5
+ krb5_init_context(&k5_context);
+ krb5_init_ets(k5_context);
+ krb5_cc_default(k5_context, &k5_ccache);
+ #endif
+
+ return TRUE;
+
+} /* init_instance */
+
+
+/*+
+ * Function: Quits the current instance of the KWIN application.
+ *
+ * Parameters:
+ * hinstance - the instance to quit.
+ *
+ * Returns: TRUE if termination was sucessfully, false otherwise.
+ */
+static BOOL
+quit_instance (
+ HINSTANCE hinstance)
+{
+ int i;
+
+ #ifdef KRB4
+ krb_end_session((char *) NULL);
+ #endif
+
+ #ifdef KRB5 /* FIXME */
+ krb5_cc_close (k5_context, k5_ccache);
+ #endif
+
+ WSACleanup();
+
+ /*
+ * Unload clock icons
+ */
+ for (i = IDI_FIRST_CLOCK; i <= IDI_LAST_CLOCK; i++)
+ DestroyIcon(kwin_icons[i - IDI_FIRST_CLOCK]);
+
+ return TRUE;
+
+} /* quit_instance */
+
+
+/*+
+ * Function: Main routine called on program invocation.
+ *
+ * Parameters:
+ * hinstance - the current instance
+ *
+ * hprevinstance - previous instance if one exists or NULL.
+ *
+ * cmdline - the command line string passed by Windows.
+ *
+ * ncmdshow - show flag to indicate wheather to come up minimized
+ * or not.
+ *
+ * Returns: TRUE if initialized sucessfully, false otherwise.
+ */
+int PASCAL
+WinMain (
+ HINSTANCE hinst,
+ HINSTANCE hprevinstance,
+ LPSTR cmdline,
+ int ncmdshow)
+{
+ DLGPROC dlgproc;
+ HWND hwnd;
+ HACCEL haccel;
+ MSG msg;
+ char *p;
+ char buf[MAX_K_NAME_SZ + 9];
+ char name[MAX_K_NAME_SZ];
+
+ strcpy(buf, cmdline);
+ action = LOGIN_AND_RUN;
+ name[0] = 0;
+ p = strtok(buf, " ,");
+
+ while (p != NULL) {
+ if (_stricmp(p, "/exit") == 0)
+ action = LOGIN_AND_EXIT;
+ else if (_stricmp(p, "/minimize") == 0)
+ action = LOGIN_AND_MINIMIZE;
+ else
+ strcpy(name, p);
+
+ p = strtok(NULL, " ,");
+ }
+
+ dlgncmdshow = ncmdshow;
+ hinstance = hinst;
+
+ /*
+ * If a previous instance of this application exits, bring it
+ * to the front and exit.
+ */
+ if (hprevinstance != NULL) {
+ hwnd = FindWindow(KWIN_DIALOG_CLASS, NULL);
+
+ if (IsWindow(hwnd) && IsWindowVisible(hwnd)) {
+ if (GetWindowWord(hwnd, GWW_HINSTANCE) == hprevinstance) {
+ if (name[0])
+ SendMessage(hwnd, WM_KWIN_SETNAME, 0, (LONG) name);
+
+ ShowWindow(hwnd, ncmdshow);
+ SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
+ SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
+
+ return FALSE;
+ }
+ }
+ }
+
+ if (hprevinstance == NULL)
+ if (!init_application(hinstance))
+ return FALSE;
+
+ if (!init_instance(hinstance, ncmdshow))
+ return FALSE;
+
+ dlgproc = (FARPROC) MakeProcInstance(kwin_dlg_proc, hinstance);
+ assert(dlgproc != NULL);
+
+ if (dlgproc == NULL)
+ return 1;
+
+ hwnd = CreateDialogParam(hinstance, MAKEINTRESOURCE (ID_KWIN),
+ HWND_DESKTOP, dlgproc, (LONG) name);
+ assert(hwnd != NULL);
+
+ if (hwnd == NULL)
+ return 1;
+ haccel = LoadAccelerators(hinstance, MAKEINTRESOURCE(IDA_KWIN));
+ assert(hwnd != NULL);
+
+ while (GetMessage(&msg, NULL, 0, 0)) {
+ if (!TranslateAccelerator(hwnd, haccel, &msg) &&
+ !IsDialogMessage(hwnd, &msg)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ DestroyWindow(hwnd);
+ FreeProcInstance((FARPROC) dlgproc);
+
+ return 0;
+
+} /* WinMain */
+
+
+#if 0
+
+ #define WM_ASYNC_COMPLETED (WM_USER + 1)
+ #define GETHOSTBYNAME_CLASS "krb_gethostbyname"
+ static HTASK htaskasync; /* Asynchronos call in progress */
+ static BOOL iscompleted; /* True when async call is completed */
+
+ /*
+ * This routine is called to cancel a blocking hook call within
+ * the Kerberos library. The need for this routine arises due
+ * to bugs which exist in existing WINSOCK implementations. We
+ * blocking gethostbyname with WSAASyncGetHostByName. In order
+ * to cancel such an operation, this routine must be called.
+ * Applications may call this routine in addition to calls to
+ * WSACancelBlockingCall to get any sucy Async calls canceled.
+ * Return values are as they would be for WSACancelAsyncRequest.
+ */
+ int
+ krb_cancel_blocking_call(void)
+ {
+ if (htaskasync == NULL)
+ return 0;
+ iscompleted = TRUE;
+
+ return WSACancelAsyncRequest(htask);
+
+ } /* krb_cancel_blocking_call */
+
+
+ /*
+ * Window proceedure for temporary Windows created in
+ * krb_gethostbyname. Fields completion messages.
+ */
+ LRESULT __export CALLBACK krb_gethostbyname_wnd_proc(
+ HWND hwnd,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam)
+ {
+ if (message == WM_ASYNC_COMPLETED) {
+ iscompleted = TRUE;
+ return 0;
+ }
+
+ return DefWindowProc(hwnd, message, wparam, lparam);
+
+ } /* krb_gethostbyname_wnd_proc */
+
+
+ /*
+ * The WINSOCK routine gethostbyname has a bug in both FTP and NetManage
+ * implementations which causes the blocking hook, if any, not to be
+ * called. This routine attempts to work around the problem by using
+ * the async routines to emulate the functionality of the synchronous
+ * routines
+ */
+ struct hostent FAR *PASCAL FAR
+ krb_gethostbyname(
+ const char FAR *name)
+ {
+ HWND hwnd;
+ char buf[MAXGETHOSTSTRUCT];
+ BOOL FARPROC blockinghook;
+ WNDCLASS wc;
+ static BOOL isregistered;
+
+ blockinghook = WSASetBlockingHook(NULL);
+ WSASetBlockingHook(blockinghook);
+
+ if (blockinghook == NULL)
+ return gethostbyname(name);
+
+ if (RegisterWndClass() == NULL)
+ return gethostbyname(name);
+
+ if (!isregistered) {
+ wc.style = 0;
+ wc.lpfnWndProc = gethostbyname_wnd_proc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = hlibinstance;
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = GETHOSTBYNAME_CLASS;
+
+ if (!RegisterClass(&wc))
+ return gethostbyname(name);
+
+ isregistered = TRUE;
+ }
+
+ hwnd = CreateWindow(GETHOSTBYNAME_CLASS, "", WS_OVERLAPPED,
+ -100, -100, 0, 0, HWND_DESKTOP, NULL, hlibinstance, NULL);
+ if (hwnd == NULL)
+ return gethostbyname(name);
+
+ htaskasync =
+ WSAAsyncGetHostByName(hwnd, WM_ASYNC_COMPLETED, name, buf, sizeof(buf));
+ b = blockinghook(NULL);
+
+ } /* krb_gethostbyname */
+
+#endif
+
+#ifdef KRB5
+
+void
+debugbox () {
+ MessageBox (NULL, "foobar", "FOOBAR", IDOK | MB_ICONINFORMATION);
+}
+
+/*+
+ * Function: destroys all tickets in a k5 ccache
+ *
+ * Parameters:
+ * none
+ *
+ * Returns: K5 error code (0 == success)
+ */
+static krb5_error_code
+k5_dest_tkt (void) {
+ krb5_error_code code;
+ krb5_principal princ;
+ char *defname; /* Name of cache */
+
+ if (code = krb5_cc_get_principal(k5_context, k5_ccache, &princ)) {
+ com_err (NULL, code, "while retrieving principal name");
+ return code;
+ }
+ if (code = krb5_unparse_name(k5_context, princ, &defname)) {
+ com_err (NULL, code, "while unparsing principal name");
+ return code;
+ }
+
+ code = krb5_cc_initialize (k5_context, k5_ccache, princ);
+ if (code != 0) {
+ com_err (NULL, code, "when re-initializing cache");
+ return code;
+ }
+
+ return code;
+}
+
+/*+
+ *
+ * k5_get_num_cred
+ *
+ * Returns: number of creds in the credential cache
+ *
+ */
+static int
+k5_get_num_cred () {
+ krb5_error_code code;
+ krb5_cc_cursor cursor;
+ krb5_creds c;
+ int ncreds = 0;
+
+ if (code = krb5_cc_start_seq_get(k5_context, k5_ccache, &cursor)) {
+ if (code != KRB5_FCC_NOFILE)
+ com_err (NULL, code, "while starting to retrieve tickets");
+ return 0;
+ }
+
+ while (1) {
+ code = krb5_cc_next_cred(k5_context, k5_ccache, &cursor, &c);
+ if (code)
+ break;
+ ++ncreds;
+ }
+
+ if (code == KRB5_CC_END) { /* End of ccache */
+ if (code = krb5_cc_end_seq_get(k5_context, k5_ccache, &cursor))
+ com_err (NULL, code, "while finishing ticket retrieval");
+ } else {
+ com_err (NULL, code, "while retrieving a ticket");
+ return 0;
+ }
+
+ return ncreds;
+}
+
+static int
+k5_get_num_cred2 () {
+ krb5_error_code code;
+ krb5_cc_cursor cursor;
+ krb5_creds c;
+ int ncreds = 0;
+
+ code = krb5_cc_start_seq_get (k5_context, k5_ccache, &cursor);
+ if (code == KRB5_FCC_NOFILE)
+ return 0;
+
+ while (1) {
+ code = krb5_cc_next_cred(k5_context, k5_ccache, &cursor, &c);
+ if (code)
+ break;
+ ++ncreds;
+ }
+ krb5_cc_end_seq_get(k5_context, k5_ccache, &cursor);
+
+ return ncreds;
+}
+
+/*+
+ * Function: Parses fullname into name, instance and realm
+ *
+ * Parameters:
+ * name - buffer filled with name of user
+ *
+ * realm - buffer filled with realm of user
+ *
+ * fullname - string in form name.instance@realm
+ *
+ * Returns: 0
+ */
+static int
+k5_kname_parse (char *name, char *realm, char *fullname) {
+ char *ptr; /* For parsing */
+
+ ptr = strchr (fullname, '@'); /* Name, realm separator */
+
+ if (ptr != NULL) { /* Get the name */
+ strncpy (name, fullname, ptr - fullname);
+ name[ptr - fullname] = '\0';
+ } else
+ strcpy (name, fullname);
+
+ if (ptr != NULL) /* Get realm */
+ strcpy (realm, ptr + 1);
+ else
+ *realm = '\0';
+
+ return 0;
+}
+#endif /* KRB5 */