#include <windows.h>
#include <windowsx.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <malloc.h>
#include <ctype.h>
#include <time.h>
#include "cns.h"
#include "tktlist.h"
#include "cns_reg.h"
#include "../lib/gic.h"
enum {
LOGIN_AND_EXIT,
LOGIN_AND_MINIMIZE,
LOGIN_AND_RUN,
};
static HICON kwin_icons[MAX_ICONS];
HFONT hfontdialog = NULL;
static HFONT hfonticon = NULL;
HINSTANCE hinstance;
static int dlgncmdshow;
#if 0
static UINT wm_kerberos_changed;
#endif
static int action;
static UINT kwin_timer_id;
BOOL alert;
BOOL beep;
static BOOL alerted;
BOOL isblocking = FALSE;
static DWORD blocking_end_time;
static FARPROC hook_instance;
char confname[FILENAME_MAX];
#ifdef KRB5
char ccname[FILENAME_MAX];
BOOL forwardable;
BOOL noaddresses;
krb5_context k5_context;
krb5_ccache k5_ccache;
#endif
BOOL 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;
}
void
start_blocking_hook(int timeout)
{
FARPROC proc;
if (isblocking)
return;
isblocking = TRUE;
blocking_end_time = GetTickCount() + (1000 * timeout);
#ifdef _WIN32
proc = WSASetBlockingHook(blocking_hook_proc);
#else
hook_instance = MakeProcInstance(blocking_hook_proc, hinstance);
proc = WSASetBlockingHook(hook_instance);
#endif
assert(proc != NULL);
}
void
end_blocking_hook(void)
{
#ifndef _WIN32
FreeProcInstance(hook_instance);
#endif
WSAUnhookBlockingHook();
isblocking = FALSE;
}
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);
}
static void
position_dialog(HWND hwnd)
{
int scrwidth, scrheight;
HDC hdc;
int x, y, cx, cy;
if (hwnd == NULL)
return;
hdc = GetDC(NULL);
scrwidth = GetDeviceCaps(hdc, HORZRES);
scrheight = GetDeviceCaps(hdc, VERTRES);
ReleaseDC(NULL, hdc);
x = cns_res.x;
y = cns_res.y;
cx = cns_res.cx;
cy = cns_res.cy;
if (x > scrwidth ||
y > scrheight ||
x + cx <= 0 ||
y + cy <= 0)
center_dialog(hwnd);
else
MoveWindow(hwnd, x, y, cx, cy, TRUE);
}
void
set_dialog_font(HWND hwnd, HFONT hfont)
{
hwnd = GetWindow(hwnd, GW_CHILD);
while (hwnd != NULL) {
SetWindowFont(hwnd, hfont, 0);
hwnd = GetWindow(hwnd, GW_HWNDNEXT);
}
}
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;
}
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);
epoch += _timezone;
return epoch;
}
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(NULL, pname, pinstance, NULL) != 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
return;
#endif
}
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
return;
#endif
}
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;
fullname[sizeof(fullname) - 1] = '\0';
strncpy(fullname, "&x ", sizeof(fullname) - 1);
strncat(fullname, name, sizeof(fullname) - 1 - strlen(fullname));
strncat(fullname, ".", sizeof(fullname) - 1 - strlen(fullname));
strncat(fullname, instance, sizeof(fullname) - 1 - strlen(fullname));
strncat(fullname, "@", sizeof(fullname) - 1 - strlen(fullname));
strncat(fullname, realm, sizeof(fullname) - 1 - strlen(fullname));
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++;
}
}
static void
kwin_init_file_menu(HWND hwnd)
{
HMENU hmenu;
int i;
char menuitem[MAX_K_NAME_SZ + 3];
int id;
BOOL rc;
hmenu = GetMenu(hwnd);
assert(hmenu != NULL);
hmenu = GetSubMenu(hmenu, 0);
assert(hmenu != NULL);
id = 0;
for (i = 0; i < FILE_MENU_MAX_LOGINS; i++) {
strcpy(menuitem + 3, cns_res.logins[i]);
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++;
}
}
static void
kwin_save_file_menu(HWND hwnd)
{
HMENU hmenu;
int i;
int id;
int ctitems;
char menuitem[MAX_K_NAME_SZ + 3];
hmenu = GetMenu(hwnd);
assert(hmenu != NULL);
hmenu = GetSubMenu(hmenu, 0);
assert(hmenu != NULL);
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);
strcpy(cns_res.logins[id], menuitem + 3);
id++;
}
}
HICON
kwin_get_icon(time_t expiration)
{
int ixicon;
time_t dt;
dt = expiration - time(NULL);
dt = dt / 60;
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];
}
void
kwin_init_name(HWND hwnd, char *fullname)
{
char name[ANAME_SZ];
char instance[INST_SZ];
char realm[REALM_SZ];
int krc;
#ifdef KRB5
krb5_error_code code;
char *ptr;
#endif
if (fullname == NULL || fullname[0] == 0) {
#ifdef KRB4
strcpy(name, krb_get_default_user());
strcpy(instance, cns_res.instance);
krc = krb_get_lrealm(realm, 1);
if (krc != KSUCCESS)
realm[0] = 0;
strcpy(realm, cns_res.realm);
#endif
#ifdef KRB5
strcpy(name, cns_res.name);
*realm = '\0';
code = krb5_get_default_realm(k5_context, &ptr);
if (!code) {
strcpy(realm, ptr);
}
strcpy(realm, cns_res.realm);
#endif
} else {
#ifdef KRB4
kname_parse(name, instance, realm, fullname);
SetDlgItemText(hwnd, IDD_LOGIN_INSTANCE, instance);
#endif
#ifdef KRB5
krc = k5_kname_parse(name, realm, fullname);
*instance = '\0';
#endif
}
SetDlgItemText(hwnd, IDD_LOGIN_NAME, name);
SetDlgItemText(hwnd, IDD_LOGIN_REALM, realm);
}
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, (WPARAM)hwnditem, MAKELONG(1, 0));
}
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);
strcpy(cns_res.instance, instance);
#endif
#ifdef KRB5
strcpy(cns_res.name, name);
*instance = '\0';
#endif
GetDlgItemText(hwnd, IDD_LOGIN_REALM, realm, sizeof(realm));
trim(realm);
strcpy(cns_res.realm, realm);
kwin_push_login(hwnd, name, instance, realm);
}
static BOOL
kwin_initdialog(HWND hwnd, HWND hwndFocus, 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;
}
static void
kwin_destroy(HWND hwnd)
{
RECT r;
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);
cns_res.x = r.left;
cns_res.y = r.top;
cns_res.cx = r.right - r.left;
cns_res.cy = r.bottom - r.top;
KillTimer(hwnd, kwin_timer_id);
}
static void
windowrect(HWND hwnditem, HWND hwnd, RECT *r)
{
GetWindowRect(hwnditem, r);
ScreenToClient(hwnd, (LPPOINT)&(r->left));
ScreenToClient(hwnd, (LPPOINT)&(r->right));
}
static void
kwin_size(HWND hwnd, UINT state, int cxdlg, int cydlg)
{
#define listgap 8
RECT r;
RECT rdlg;
int hmargin, vmargin;
HWND hwnditem;
int cx, cy;
int i;
int titlebottom;
int editbottom;
int listbottom;
int gap;
int left;
int titleleft[IDD_MAX_TITLE - IDD_MIN_TITLE + 1];
if (state == SIZE_MINIMIZED)
return;
GetClientRect(hwnd, &rdlg);
hwnditem = GetDlgItem(hwnd, IDD_TICKET_LIST_TITLE);
if (hwnditem == NULL)
return;
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);
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;
}
editbottom += r.top;
hwnditem = GetDlgItem(hwnd, IDD_MIN_EDIT);
windowrect(hwnditem, hwnd, &r);
gap = r.right;
hmargin = r.left;
editbottom += r.bottom;
titlebottom = -r.top;
hwnditem = GetDlgItem(hwnd, IDD_MIN_EDIT + 1);
windowrect(hwnditem, hwnd, &r);
gap = r.left - gap;
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;
}
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);
}
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);
}
static void
kwin_getminmaxinfo(HWND hwnd, LPMINMAXINFO lpmmi)
{
lpmmi->ptMinTrackSize.x =
(KWIN_MIN_WIDTH * LOWORD(GetDialogBaseUnits())) / 4;
lpmmi->ptMinTrackSize.y =
(KWIN_MIN_HEIGHT * HIWORD(GetDialogBaseUnits())) / 8;
}
static void
kwin_timer(HWND hwnd, UINT timer_id)
{
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 (timer_id != 1) {
FORWARD_WM_TIMER(hwnd, timer_id, DefDlgProc);
return;
}
expired = FALSE;
ticket_init_list(GetDlgItem(hwnd, IDD_TICKET_LIST));
if (alerted) {
if (IsIconic(hwnd))
InvalidateRect(hwnd, NULL, TRUE);
return;
}
#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) {
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;
if (t >= expiration + KWIN_UPDATE_PERIOD / 1000) {
alerted = TRUE;
if (IsIconic(hwnd))
InvalidateRect(hwnd, NULL, TRUE);
return;
}
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;
expiration = cred.times.endtime;
t = TIME_BUFFER + time(NULL);
if (t >= expiration) {
expired = TRUE;
if (t >= expiration + KWIN_UPDATE_PERIOD / 1000) {
alerted = TRUE;
if (IsIconic(hwnd))
InvalidateRect(hwnd, NULL, TRUE);
return;
}
break;
}
}
if (code == 0 || code == KRB5_CC_END)
krb5_cc_end_seq_get(k5_context, k5_ccache, &cursor);
#endif
if (!expired) {
if (IsIconic(hwnd))
InvalidateRect(hwnd, NULL, TRUE);
return;
}
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;
}
if (IsIconic(hwnd))
InvalidateRect(hwnd, NULL, TRUE);
}
static void
kwin_command(HWND hwnd, int cid, HWND hwndCtl, UINT codeNotify)
{
char name[ANAME_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];
int id;
#ifdef KRB4
char instance[INST_SZ];
int lifetime;
int krc;
#endif
#ifdef KRB5
long lifetime;
krb5_error_code code;
krb5_principal principal;
krb5_creds creds;
krb5_get_init_creds_opt opts;
gic_data gd;
#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(1) > 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);
id = (blogin) ? IDD_LOGIN : IDD_PASSWORD_CR2;
SendMessage(hwnd, DM_SETDEFID, id, 0);
if (codeNotify != BN_CLICKED && codeNotify != 0 && codeNotify != 1)
return;
if (cid >= IDM_FIRST_LOGIN && cid < IDM_FIRST_LOGIN + FILE_MENU_MAX_LOGINS) {
hmenu = GetMenu(hwnd);
assert(hmenu != NULL);
hmenu = GetSubMenu(hmenu, 0);
assert(hmenu != NULL);
if (!GetMenuString(hmenu, cid, menuitem, sizeof(menuitem), MF_BYCOMMAND))
return;
if (menuitem[0])
kwin_init_name(hwnd, &menuitem[3]);
return;
}
switch (cid) {
case IDM_EXIT:
if (isblocking)
WSACancelBlockingCall();
WinHelp(hwnd, KERBEROS_HLP, HELP_QUIT, 0);
PostQuitMessage(0);
return;
case IDD_PASSWORD_CR2:
id = GetDlgCtrlID(GetFocus());
assert(id != 0);
if (id == IDD_MAX_EDIT)
PostMessage(hwnd, WM_NEXTDLGCTL,
(WPARAM)GetDlgItem(hwnd, IDD_MIN_EDIT), MAKELONG(1, 0));
else
PostMessage(hwnd, WM_NEXTDLGCTL, 0, 0);
return;
case IDD_LOGIN:
if (isblocking)
return;
GetDlgItemText(hwnd, IDD_LOGIN_NAME, name, sizeof(name));
trim(name);
GetDlgItemText(hwnd, IDD_LOGIN_REALM, realm, sizeof(realm));
trim(realm);
GetDlgItemText(hwnd, IDD_LOGIN_PASSWORD, password, sizeof(password));
SetDlgItemText(hwnd, IDD_LOGIN_PASSWORD, "");
trim(password);
#ifdef KRB4
GetDlgItemText(hwnd, IDD_LOGIN_INSTANCE, instance, sizeof(instance));
trim(instance);
#endif
hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
lifetime = cns_res.lifetime;
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
principal = NULL;
sprintf(menuitem, "%s@%s", name, realm);
code = krb5_parse_name(k5_context, menuitem, &principal);
if (code)
goto errorpoint;
krb5_get_init_creds_opt_init(&opts);
krb5_get_init_creds_opt_set_forwardable(&opts, forwardable);
krb5_get_init_creds_opt_set_tkt_life(&opts, lifetime * 60);
if (noaddresses) {
krb5_get_init_creds_opt_set_address_list(&opts, NULL);
}
gd.hinstance = hinstance;
gd.hwnd = hwnd;
gd.id = ID_VARDLG;
code = krb5_get_init_creds_password(k5_context, &creds, principal, password,
gic_prompter, &gd, 0, NULL, &opts);
if (code)
goto errorpoint;
code = krb5_cc_initialize(k5_context, k5_ccache, principal);
if (code)
goto errorpoint;
code = krb5_cc_store_cred(k5_context, k5_ccache, &creds);
errorpoint:
if (principal)
krb5_free_principal(k5_context, principal);
end_blocking_hook();
SetCursor(hcursor);
kwin_set_default_focus(hwnd);
if (code) {
if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY)
MessageBox(hwnd, "Password incorrect", NULL,
MB_OK | MB_ICONEXCLAMATION);
else
com_err(NULL, code, "while logging in");
}
#endif
#ifdef KRB4
if (krc != KSUCCESS) {
MessageBox(hwnd, krb_get_err_text(krc), "",
MB_OK | MB_ICONEXCLAMATION);
return;
}
#endif
kwin_save_name(hwnd);
alerted = FALSE;
switch (action) {
case LOGIN_AND_EXIT:
SendMessage(hwnd, WM_COMMAND, GET_WM_COMMAND_MPS(IDM_EXIT, 0, 0));
break;
case LOGIN_AND_MINIMIZE:
ShowWindow(hwnd, SW_MINIMIZE);
break;
}
return;
case IDD_TICKET_DELETE:
if (isblocking)
return;
#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();
#endif
kwin_set_default_focus(hwnd);
alerted = FALSE;
return;
case IDD_CHANGE_PASSWORD:
if (isblocking)
return;
password_dialog(hwnd);
kwin_set_default_focus(hwnd);
return;
case IDM_OPTIONS:
if (isblocking)
return;
opts_dialog(hwnd);
return;
case IDM_HELP_INDEX:
WinHelp(hwnd, KERBEROS_HLP, HELP_INDEX, 0);
return;
case IDM_ABOUT:
ticket_init_list(GetDlgItem(hwnd, IDD_TICKET_LIST));
if (isblocking)
return;
#ifdef KRB4
strcpy(copyright, " Kerberos 4 for Windows ");
#endif
#ifdef KRB5
strcpy(copyright, " Kerberos V5 for Windows ");
#endif
#ifdef _WIN32
strncat(copyright, "32-bit\n", sizeof(copyright) - 1 - strlen(copyright));
#else
strncat(copyright, "16-bit\n", sizeof(copyright) - 1 - strlen(copyright));
#endif
strncat(copyright, "\n Version 1.12\n\n",
sizeof(copyright) - 1 - strlen(copyright));
#ifdef ORGANIZATION
strncat(copyright, " For information, contact:\n",
sizeof(copyright) - 1 - strlen(copyright));
strncat(copyright, ORGANIZATION, sizeof(copyright) - 1 - strlen(copyright));
#endif
MessageBox(hwnd, copyright, KWIN_DIALOG_NAME, MB_OK);
return;
}
return;
}
static void
kwin_syscommand(HWND hwnd, UINT cmd, int x, int y)
{
if (cmd == SC_RESTORE)
kwin_set_default_focus(hwnd);
if (cmd == SC_CLOSE) {
SendMessage(hwnd, WM_COMMAND, GET_WM_COMMAND_MPS(IDM_EXIT, 0, 0));
return;
}
FORWARD_WM_SYSCOMMAND(hwnd, cmd, x, y, DefDlgProc);
}
static void
kwin_paint(HWND hwnd)
{
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)) {
FORWARD_WM_PAINT(hwnd, DefDlgProc);
return;
}
#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;
}
if (code == 0 || code == KRB5_CC_END)
krb5_cc_end_seq_get(k5_context, k5_ccache, &cursor);
#endif
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &r);
DefWindowProc(hwnd, WM_ICONERASEBKGND, (WPARAM)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);
}
buf[sizeof(buf) - 1] = '\0';
if (dt > 1)
strncat(buf, "s", sizeof(buf) - 1 - strlen(buf));
}
DrawIcon(hdc, r.left, r.top, hicon);
EndPaint(hwnd, &ps);
SetWindowText(hwnd, buf);
}
LRESULT CALLBACK
kwin_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
#if 0
if (message == wm_kerberos_changed) {
n = ticket_init_list(GetDlgItem(hwnd, IDD_TICKET_LIST));
EnableWindow(GetDlgItem(hwnd, IDD_TICKET_DELETE), n > 0);
return 0;
}
#endif
switch (message) {
HANDLE_MSG(hwnd, WM_GETMINMAXINFO, kwin_getminmaxinfo);
HANDLE_MSG(hwnd, WM_DESTROY, kwin_destroy);
HANDLE_MSG(hwnd, WM_MEASUREITEM, ticket_measureitem);
HANDLE_MSG(hwnd, WM_DRAWITEM, ticket_drawitem);
case WM_SETCURSOR:
if (isblocking) {
SetCursor(LoadCursor(NULL, IDC_WAIT));
return TRUE;
}
break;
HANDLE_MSG(hwnd, WM_SIZE, kwin_size);
HANDLE_MSG(hwnd, WM_SYSCOMMAND, kwin_syscommand);
HANDLE_MSG(hwnd, WM_TIMER, kwin_timer);
HANDLE_MSG(hwnd, WM_PAINT, kwin_paint);
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);
}
static BOOL CALLBACK
kwin_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
HANDLE_MSG(hwnd, WM_INITDIALOG, kwin_initdialog);
HANDLE_MSG(hwnd, WM_COMMAND, kwin_command);
}
return FALSE;
}
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;
class.hCursor = NULL;
class.hbrBackground = NULL;
class.lpszMenuName = NULL;
class.lpszClassName = KWIN_DIALOG_CLASS;
rc = RegisterClass(&class);
assert(rc);
return rc;
}
static BOOL
init_application(HINSTANCE hinstance)
{
BOOL rc;
#if 0
#ifdef KRB4
wm_kerberos_changed = krb_get_notification_message();
#endif
#ifdef KRB5
wm_kerberos_changed = krb5_get_notification_message();
#endif
#endif
rc = kwin_init(hinstance);
return rc;
}
static BOOL
quit_application(HINSTANCE hinstance)
{
return TRUE;
}
static BOOL
init_instance(HINSTANCE hinstance, int ncmdshow)
{
WORD versionrequested;
WSADATA wsadata;
int rc;
int i;
versionrequested = 0x0101;
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;
}
#ifdef KRB5
{
krb5_error_code code;
code = krb5_init_context(&k5_context);
if (!code) {
#if 0
krb5_init_ets(k5_context);
#endif
code = k5_init_ccache(&k5_ccache);
}
if (code) {
com_err(NULL, code, "while initializing program");
return FALSE;
}
k5_name_from_ccache(k5_ccache);
}
#endif
cns_load_registry();
alert = cns_res.alert;
beep = cns_res.beep;
forwardable = cns_res.forwardable;
noaddresses = cns_res.noaddresses;
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
return TRUE;
}
static BOOL
quit_instance(HINSTANCE hinstance)
{
int i;
#ifdef KRB4
krb_end_session(NULL);
#endif
#ifdef KRB5
krb5_cc_close(k5_context, k5_ccache);
#endif
WSACleanup();
for (i = IDI_FIRST_CLOCK; i <= IDI_LAST_CLOCK; i++)
DestroyIcon(kwin_icons[i - IDI_FIRST_CLOCK]);
return TRUE;
}
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;
#ifndef _WIN32
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)
#endif
if (!init_application(hinstance))
return FALSE;
if (!init_instance(hinstance, ncmdshow))
return FALSE;
#ifdef _WIN32
dlgproc = kwin_dlg_proc;
#else
dlgproc = (FARPROC)MakeProcInstance(kwin_dlg_proc, hinstance);
assert(dlgproc != NULL);
if (dlgproc == NULL)
return 1;
#endif
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);
#ifndef _WIN32
FreeProcInstance((FARPROC)dlgproc);
#endif
cns_save_registry();
return 0;
}
#if 0
#define WM_ASYNC_COMPLETED (WM_USER + 1)
#define GETHOSTBYNAME_CLASS "krb_gethostbyname"
static HTASK htaskasync;
static BOOL iscompleted;
int
krb_cancel_blocking_call(void)
{
if (htaskasync == NULL)
return 0;
iscompleted = TRUE;
return WSACancelAsyncRequest(htask);
}
LRESULT 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);
}
struct hostent *PASCAL
krb_gethostbyname(
const char *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);
}
#endif
#ifdef KRB5
krb5_error_code
k5_dest_tkt(void)
{
krb5_error_code code;
krb5_principal princ;
if (code = krb5_cc_get_principal(k5_context, k5_ccache, &princ)) {
com_err(NULL, code, "while retrieving principal name");
return code;
}
code = krb5_cc_initialize(k5_context, k5_ccache, princ);
if (code != 0) {
com_err(NULL, code, "when re-initializing cache");
krb5_free_principal(k5_context, princ);
return code;
}
krb5_free_principal(k5_context, princ);
return code;
}
int
k5_get_num_cred(int verbose)
{
krb5_error_code code;
krb5_cc_cursor cursor;
krb5_creds c;
int ncreds = 0;
if (code = krb5_cc_set_flags(k5_context, k5_ccache, 0)) {
if (code == KRB5_FCC_NOFILE)
return 0;
if (verbose)
com_err(NULL, code,
"while setting cache flags (ticket cache %s)",
krb5_cc_get_name(k5_context, k5_ccache));
return -1;
}
if (code = krb5_cc_start_seq_get(k5_context, k5_ccache, &cursor)) {
if (verbose)
com_err(NULL, code, "while starting to retrieve tickets.");
return -1;
}
while (1) {
code = krb5_cc_next_cred(k5_context, k5_ccache, &cursor, &c);
if (code)
break;
++ncreds;
}
if (code != KRB5_CC_END) {
if (verbose)
com_err(NULL, code, "while retrieving a ticket.");
return -1;
}
if (code = krb5_cc_end_seq_get(k5_context, k5_ccache, &cursor)) {
if (verbose)
com_err(NULL, code, "while closing ccache.");
} else if (code = krb5_cc_set_flags(k5_context, k5_ccache,
KRB5_TC_OPENCLOSE)) {
if (verbose)
com_err(NULL, code, "while closing ccache.");
}
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;
}
if (code == KRB5_CC_END)
krb5_cc_end_seq_get(k5_context, k5_ccache, &cursor);
return ncreds;
}
int
k5_kname_parse(char *name, char *realm, char *fullname)
{
char *ptr;
ptr = strchr(fullname, '@');
if (ptr != NULL)
strcpy(realm, ptr + 1);
else
*realm = '\0';
if (ptr != NULL) {
strncpy(name, fullname, ptr - fullname);
name[ptr - fullname] = '\0';
} else
strcpy(name, fullname);
ptr = strchr(name, '.');
if (ptr != NULL)
*ptr = '\0';
return 0;
}
krb5_error_code
k5_init_ccache(krb5_ccache *ccache)
{
krb5_error_code code;
krb5_principal princ;
FILE *fp;
code = krb5_cc_default(k5_context, ccache);
if (code)
return code;
code = krb5_cc_get_principal(k5_context, *ccache, &princ);
if (code == KRB5_FCC_NOFILE) {
fp = fopen(krb5_cc_get_name(k5_context, *ccache), "w");
if (fp == NULL)
return KRB5_FCC_PERM;
fclose (fp);
}
if (code) {
remove(krb5_cc_get_name(k5_context, *ccache));
code = krb5_cc_get_principal(k5_context, *ccache, &princ);
if (code == KRB5_FCC_NOFILE)
return 0;
if (code)
return code;
}
return 0;
}
int
k5_name_from_ccache(krb5_ccache k5_ccache)
{
krb5_error_code code;
krb5_principal princ;
char name[ANAME_SZ];
char realm[REALM_SZ];
char *defname;
if (code = krb5_cc_get_principal(k5_context, k5_ccache, &princ))
return FALSE;
code = krb5_unparse_name(k5_context, princ, &defname);
if (code) {
return FALSE;
}
k5_kname_parse(name, realm, defname);
strcpy(cns_res.name, name);
strcpy(cns_res.realm, realm);
return TRUE;
}
#endif