50cf1cdd2cebc9028ff4fbdb30909a044db8f69b
[krb5.git] / src / windows / cns / cns.c
1 /*
2  * cns.c
3  *
4  * Tabs 4
5  *
6  * Main routine of the Kerberos user interface.  Also handles
7  * all dialog level management functions.
8  *
9  * Copyright 1994 by the Massachusetts Institute of Technology.
10  *
11  * For copying and distribution information, please see the file
12  * <mit-copyright.h>.
13  */
14
15 #if !defined(KRB5) && !defined(KRB4)
16         #define KRB5 1
17 #endif
18
19 #include <windows.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <assert.h>
23 #include <string.h>
24 #include <malloc.h>
25 #include <ctype.h>
26 #include <time.h>
27
28 #ifdef KRB4
29         #define DEFINE_SOCKADDR
30         #include "mit-copyright.h"
31         #include "krb.h"
32         #include "kadm.h"
33         #include "org.h"
34 #endif
35
36 #ifdef KRB5
37         #define NEED_SOCKETS
38         #include "krb5.h"
39         #include "krbini.h"
40         #include "com_err.h"
41
42         #define DEFAULT_TKT_LIFE    120             // In 5 minute units
43         #define ANAME_SZ                40
44         #define REALM_SZ                40
45         #define SNAME_SZ                40
46         #define INST_SZ                 40
47         #define MAX_KPW_LEN             128
48         /* include space for '.' and '@' */
49         #define MAX_K_NAME_SZ       (ANAME_SZ + INST_SZ + REALM_SZ + 2)
50         #define ORGANIZATION        "Cygnus Support"
51
52     #define CREDENTIALS         char
53 #endif
54
55 #include "cns.h"
56 #include "tktlist.h"
57
58 /*
59  * Constants
60  */
61 #define BLOCK_MAX_SEC 30                                /* Blocking timeout duration */
62 #define KWIN_UPDATE_PERIOD 30000                /* Every 30 seconds update the screen */
63 #define TIME_BUFFER     300                                     /* Pop-up time buffer in seconds */
64 #define WM_KWIN_SETNAME (WM_USER+100)   /* Sets the name fields in the dialog */
65
66 enum {                                                                  /* Actions after login */
67         LOGIN_AND_EXIT,
68         LOGIN_AND_MINIMIZE,
69         LOGIN_AND_RUN,
70 };
71
72 /*
73  * Globals
74  */
75 static HICON kwin_icons[MAX_ICONS];             /* Icons depicting time */
76 static HFONT hfontdialog = NULL;                /* Font in which the dialog is drawn. */
77 static HFONT hfonticon = NULL;                  /* Font for icon label */
78 static HINSTANCE hinstance;
79 static int dlgncmdshow;                                 /* ncmdshow from WinMain */
80 static UINT wm_kerberos_changed;                /* Registered message for cache changing */
81 static int action;                                              /* After login actions */
82 static UINT kwin_timer_id;                              /* Timer being used for update */
83 static BOOL alert;                                              /* Actions on ticket expiration */
84 static BOOL beep;
85 static BOOL alerted;                                    /* TRUE when user already alerted */
86 static BOOL isblocking = FALSE;                 /* TRUE when blocked in WinSock */
87 static DWORD blocking_end_time;                 /* Ending tick count for blocking timeout */
88 static FARPROC hook_instance;                   /* Intance handle for blocking hook function */
89
90 #ifdef KRB5
91         krb5_context k5_context;
92         krb5_ccache k5_ccache;
93     static char ccname[FILENAME_MAX];           /* ccache file location */
94 #endif
95
96 /*+
97  * Function: Called during blocking operations.  Implement a timeout
98  *      if nothing occurs within the specified time, cancel the blocking
99  *      operation.  Also permit the user to press escape in order to
100  *      cancel the blocking operation.
101  *
102  * Returns: TRUE if we got and dispatched a message, FALSE otherwise.
103  */
104 BOOL __export CALLBACK
105 blocking_hook_proc (void)
106 {
107         MSG msg;
108         BOOL rc;
109
110         if (GetTickCount() > blocking_end_time) {
111                 WSACancelBlockingCall();
112                 return FALSE;
113         }
114
115         rc = (BOOL) PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
116         if (!rc)
117                 return FALSE;
118
119         if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE) {
120                 WSACancelBlockingCall();
121                 blocking_end_time = msg.time - 1;
122                 return FALSE;
123         }
124
125         TranslateMessage(&msg);
126         DispatchMessage(&msg);
127
128         return TRUE;
129
130 } /* blocking_hook_proc */
131
132
133 /*+
134  * Function: Set up a blocking hook function.
135  *
136  * Parameters:
137  *      timeout - # of seconds to block for before cancelling.
138  */
139 static void
140 start_blocking_hook (
141         int timeout)
142 {
143         FARPROC proc;
144
145         if (isblocking)
146                 return;
147
148         isblocking = TRUE;
149         blocking_end_time = GetTickCount() + (1000 * timeout);
150         hook_instance = MakeProcInstance(blocking_hook_proc, hinstance);
151         proc = WSASetBlockingHook(hook_instance);
152         assert(proc != NULL);
153
154 } /* start_blocking_hook */
155
156
157 /*+
158  * Function: End the blocking hook fuction set up above.
159  */
160 static void
161 end_blocking_hook (void)
162 {
163
164         FreeProcInstance(hook_instance);
165         WSAUnhookBlockingHook();
166         isblocking = FALSE;
167
168 } /* end_blocking_hook */
169
170
171 /*+
172  * Function: Centers the specified window on the screen.
173  *
174  * Parameters:
175  *              hwnd - the window to center on the screen.
176  */
177 static void
178 center_dialog (
179         HWND hwnd)
180 {
181         int scrwidth, scrheight;
182         int dlgwidth, dlgheight;
183         RECT r;
184         HDC hdc;
185
186         if (hwnd == NULL)
187                 return;
188
189         GetWindowRect(hwnd, &r);
190         dlgwidth = r.right  - r.left;
191         dlgheight = r.bottom - r.top ;
192         hdc = GetDC(NULL);
193         scrwidth = GetDeviceCaps(hdc, HORZRES);
194         scrheight = GetDeviceCaps(hdc, VERTRES);
195         ReleaseDC(NULL, hdc);
196         r.left = (scrwidth - dlgwidth) / 2;
197         r.top  = (scrheight - dlgheight) / 2;
198         MoveWindow(hwnd, r.left, r.top, dlgwidth, dlgheight, TRUE);
199
200 } /* center_dialog */
201
202
203 /*+
204  * Function: Positions the kwin dialog either to the saved location
205  *      or the center of the screen if no saved location.
206  *
207  * Parameters:
208  *              hwnd - the window to center on the screen.
209  */
210 static void
211 position_dialog (
212         HWND hwnd)
213 {
214         int n;
215         int scrwidth, scrheight;
216         HDC hdc;
217         char position[256];
218         int x, y, cx, cy;
219
220         if (hwnd == NULL)
221                 return;
222
223         hdc = GetDC(NULL);
224         scrwidth = GetDeviceCaps(hdc, HORZRES);
225         scrheight = GetDeviceCaps(hdc, VERTRES);
226         ReleaseDC(NULL, hdc);
227         GetPrivateProfileString(INI_DEFAULTS, INI_POSITION, "",
228                 position, sizeof(position), KERBEROS_INI);
229
230         n = sscanf(position, " [%d , %d , %d , %d", &x, &y, &cx, &cy);
231         if (n != 4 ||
232                 x > scrwidth ||
233                 y > scrheight ||
234                 x + cx < 0 ||
235                 y + cy < 0)
236                 center_dialog(hwnd);
237     else
238                 MoveWindow(hwnd, x, y, cx, cy, TRUE);
239
240 } /* position_dialog */
241
242
243 /*+
244  * Function: Set font of all dialog items.
245  *
246  * Parameters:
247  *              hwnd - the dialog to set the font of
248  */
249 static void
250 set_dialog_font (
251         HWND hwnd,
252         HFONT hfont)
253 {
254         hwnd = GetWindow(hwnd, GW_CHILD);
255
256         while (hwnd != NULL) {
257                 SendMessage(hwnd, WM_SETFONT, (WPARAM) hfont, 0);
258                 hwnd = GetWindow(hwnd, GW_HWNDNEXT);
259         }
260
261 } /* set_dialog_font */
262
263
264 /*+
265  * Function: Trim leading and trailing white space from a string.
266  *
267  * Parameters:
268  *      s - the string to trim.
269  */
270 void
271 trim (
272         char *s)
273 {
274         int l;
275         int i;
276
277         for (i = 0; s[i]; i++)
278                 if (s[i] != ' ' && s[i] != '\t')
279                         break;
280
281         l = strlen(&s[i]);
282         memmove(s, &s[i], l + 1);
283
284         for (l--; l >= 0; l--) {
285                 if (s[l] != ' ' && s[l] != '\t')
286                         break;
287         }
288         s[l + 1] = 0;
289
290 } /* trim */
291
292
293 /*+
294  * Function: This routine figures out the current time epoch and
295  * returns the conversion factor.  It exists because Microloss
296  * screwed the pooch on the time() and _ftime() calls in its release
297  * 7.0 libraries.  They changed the epoch to Dec 31, 1899!
298  */
299 time_t
300 kwin_get_epoch (void)
301 {
302         static struct tm jan_1_70 = {0, 0, 0, 1, 0, 70};
303         time_t epoch = 0;
304
305         epoch = -mktime(&jan_1_70);             /* Seconds til 1970 localtime */
306         epoch += _timezone;                             /* Seconds til 1970 GMT */
307
308         return epoch;
309
310 } /* kwin_get_epoch */
311
312
313 /*+
314  * Function: Save the credentials for later restoration.
315  *
316  * Parameters:
317  *      c - Returned pointer to saved credential cache.
318  *
319  *      pname - Returned as principal name of session.
320  *
321  *      pinstance - Returned as principal instance of session.
322  *
323  *      ncred - Returned number of credentials saved.
324  */
325 static void
326 push_credentials (
327         CREDENTIALS **cp,
328         char *pname,
329         char *pinstance,
330         int *ncred)
331 {
332 #ifdef KRB4
333         int i;
334     char service[ANAME_SZ];
335     char instance[INST_SZ];
336     char realm[REALM_SZ];
337         CREDENTIALS *c;
338
339         if (krb_get_tf_fullname ((char *) 0, pname, pinstance, (char *) 0) != KSUCCESS) {
340                 pname[0] = 0;
341
342                 pinstance[0] = 0;
343         }
344
345         *ncred = krb_get_num_cred();
346         if (*ncred <= 0)
347                 return;
348
349         c= malloc(*ncred * sizeof(CREDENTIALS));
350         assert(c != NULL);
351         if (c == NULL) {
352                 *ncred = 0;
353
354                 return;
355         }
356
357         for (i = 0; i < *ncred; i++) {
358                 krb_get_nth_cred(service, instance, realm, i + 1);
359                 krb_get_cred(service, instance, realm, &c[i]);
360         }
361
362         *cp = c;
363 #endif
364
365 #ifdef KRB5     /* FIXME */
366     return;
367 #endif
368
369 } /* push_credentials */
370
371
372 /*+
373  * Function: Restore the saved credentials.
374  *
375  *      c - Pointer to saved credential cache.
376  *
377  *      pname - Principal name of session.
378  *
379  *      pinstance - Principal instance of session.
380  *
381  *      ncred - Number of credentials saved.
382  */
383 static void
384 pop_credentials (
385         CREDENTIALS *c,
386         char *pname,
387         char *pinstance,
388         int ncred)
389 {
390 #ifdef KRB4
391         int i;
392
393         if (pname[0])
394                 in_tkt(pname, pinstance);
395         else
396                 dest_tkt();
397
398         if (ncred <= 0)
399                 return;
400
401         for (i = 0; i < ncred; i++) {
402                 krb_save_credentials(c[i].service, c[i].instance, c[i].realm,
403                         c[i].session, c[i].lifetime, c[i].kvno, &(c[i].ticket_st),
404                         c[i].issue_date);
405         }
406
407         free(c);
408 #endif
409 #ifdef KRB5     /* FIXME */
410     return;
411 #endif
412
413 } /* pop_credentials */
414
415
416 /*+
417  * Function: Changes the password.
418  *
419  * Parameters:
420  *      hwnd - the current window from which command was invoked.
421  *
422  *      name - name of user to change password for
423  *
424  *      instance - instance of user to change password for
425  *
426  *      realm - realm in which to change password
427  *
428  *      oldpw - the old password
429  *
430  *      newpw - the new password to change to
431  *
432  * Returns: TRUE if change took place, FALSE otherwise.
433  */
434 static BOOL
435 change_password (
436         HWND hwnd,
437         char *name,
438         char *instance,
439         char *realm,
440         char *oldpw,
441         char *newpw)
442 {
443 #ifdef KRB4
444     des_cblock new_key;
445     char *ret_st;
446         int krc;
447         char *p;
448         CREDENTIALS *c;
449         int ncred;
450     char pname[ANAME_SZ];
451     char pinstance[INST_SZ];
452
453         push_credentials(&c, pname, pinstance, &ncred);
454         krc = krb_get_pw_in_tkt(
455                 name, instance, realm, PWSERV_NAME, KADM_SINST, 1, oldpw);
456
457         if (krc != KSUCCESS) {
458                 if (krc == INTK_BADPW)
459                         p = "Old password is incorrect";
460                 else
461                         p = krb_get_err_text(krc);
462                 pop_credentials(c, pname, pinstance, ncred);
463                 MessageBox(hwnd, p, "", MB_OK | MB_ICONEXCLAMATION);
464
465                 return FALSE;
466     }
467
468         krc = kadm_init_link(PWSERV_NAME, KRB_MASTER, realm);
469
470         if (krc != KSUCCESS) {
471                 pop_credentials(c, pname, pinstance, ncred);
472                 MessageBox(hwnd, kadm_get_err_text(krc), "", MB_OK | MB_ICONEXCLAMATION);
473
474                 return FALSE;
475         }
476
477         des_string_to_key(newpw, new_key);
478         krc = kadm_change_pw2(new_key, newpw, &ret_st);
479         pop_credentials(c, pname, pinstance, ncred);
480
481         if (ret_st != NULL)
482                 free(ret_st);
483
484         if (krc != KSUCCESS) {
485                 MessageBox(hwnd, kadm_get_err_text(krc), "", MB_OK | MB_ICONEXCLAMATION);
486
487                 return FALSE;
488         }
489
490         return TRUE;
491 #endif
492
493 #ifdef KRB5     /* FIXME */
494     char *msg;                                  // Message string
495     krb5_error_code code;                       // Return value
496
497     krb5_error_code //FIXME INTERFACE
498     krb5_change_password(
499            krb5_context context,
500            char *user,
501            char *realm,
502            char *old_password,
503            char *new_password,
504        char **text);
505
506     code = krb5_change_password (k5_context, name, realm, oldpw, newpw, &msg);
507
508     if (msg != NULL) {
509         MessageBox (NULL, msg, NULL, MB_ICONEXCLAMATION);
510         //WHO FREES THIS SPACE??? free (msg);
511     } else if (code)
512         com_err (NULL, code, "while changing password.");
513
514         return (code == 0);
515 #endif
516
517 } /* change_password */
518 /*+*/
519 #ifdef KRB5
520 krb5_error_code //FIXME INTERFACE
521 krb5_change_password(
522     krb5_context context,
523         char *user,
524         char *realm,
525         char *old_password,
526         char *new_password,
527     char **text)
528 {
529     *text = "Changing passwords is not yet implemented";
530     return -1;
531 }
532 #endif /* KRB5 */
533 /*+
534  * Function: Process WM_COMMAND messages for the password dialog.
535  *
536  * Parameters:
537  *      hwnd - the window recieving the message.
538  *
539  *      wparam - id of the command item
540  *
541  *      lparam - LOWORD=hwnd of control, HIWORD=notification message.
542  *
543  * Returns: TRUE if initialized sucessfully, false otherwise.
544  */
545 static LONG
546 password_command (
547         HWND hwnd,
548         WPARAM wparam,
549         LPARAM lparam)
550 {
551         char name[ANAME_SZ];
552         char instance[INST_SZ];
553         char realm[REALM_SZ];
554     char oldpw[MAX_KPW_LEN];
555     char newpw1[MAX_KPW_LEN];
556     char newpw2[MAX_KPW_LEN];
557         HCURSOR hcursor;
558         BOOL b;
559         int id;
560
561         if (HIWORD(lparam) != BN_CLICKED) {
562                 GetDlgItemText(hwnd, IDD_PASSWORD_NAME, name, sizeof(name));
563                 trim(name);
564                 GetDlgItemText(hwnd, IDD_PASSWORD_REALM, realm, sizeof(realm));
565                 trim(realm);
566                 GetDlgItemText(hwnd, IDD_OLD_PASSWORD, oldpw, sizeof(oldpw));
567                 GetDlgItemText(hwnd, IDD_NEW_PASSWORD1, newpw1, sizeof(newpw1));
568                 GetDlgItemText(hwnd, IDD_NEW_PASSWORD2, newpw2, sizeof(newpw2));
569                 b = strlen(name) && strlen(realm) && strlen(oldpw) &&
570                         strlen(newpw1) && strlen(newpw2);
571                 EnableWindow(GetDlgItem(hwnd, IDOK), b);
572                 id = (b) ? IDOK : IDD_PASSWORD_CR;
573                 SendMessage(hwnd, DM_SETDEFID, id, 0);
574
575                 return FALSE;
576         }
577
578         switch (wparam) {
579         case IDOK:
580                 if (isblocking)
581                         return TRUE;
582
583                 GetDlgItemText(hwnd, IDD_PASSWORD_NAME, name, sizeof(name));
584                 trim(name);
585         GetDlgItemText(hwnd, IDD_PASSWORD_INSTANCE, instance, sizeof(instance));
586         trim(instance);
587                 GetDlgItemText(hwnd, IDD_PASSWORD_REALM, realm, sizeof(realm));
588                 trim(realm);
589                 GetDlgItemText(hwnd, IDD_OLD_PASSWORD, oldpw, sizeof(oldpw));
590                 GetDlgItemText(hwnd, IDD_NEW_PASSWORD1, newpw1, sizeof(newpw1));
591                 GetDlgItemText(hwnd, IDD_NEW_PASSWORD2, newpw2, sizeof(newpw2));
592
593                 if (strcmp(newpw1, newpw2) != 0) {
594                         MessageBox(hwnd, "The two passwords you entered don't match!", "",
595                                 MB_OK | MB_ICONEXCLAMATION);
596                         SetDlgItemText(hwnd, IDD_NEW_PASSWORD1, "");
597                         SetDlgItemText(hwnd, IDD_NEW_PASSWORD2, "");
598                         PostMessage(hwnd, WM_NEXTDLGCTL,
599                                 GetDlgItem(hwnd, IDD_NEW_PASSWORD1), MAKELONG(1, 0));
600
601                         return TRUE;
602                 }
603
604                 hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
605                 start_blocking_hook(BLOCK_MAX_SEC);
606
607                 if (change_password(hwnd, name, instance, realm, oldpw, newpw1))
608                         EndDialog(hwnd, IDOK);
609                 else
610                         PostMessage(hwnd, WM_NEXTDLGCTL,
611                                 GetDlgItem(hwnd, IDD_OLD_PASSWORD), MAKELONG(1, 0));
612
613                 end_blocking_hook();
614                 SetCursor(hcursor);
615
616                 return TRUE;
617
618         case IDCANCEL:
619                 if (isblocking)
620                         WSACancelBlockingCall();
621                 EndDialog(hwnd, IDCANCEL);
622
623                 return TRUE;
624
625         case IDD_PASSWORD_CR:
626                 id = GetDlgCtrlID(GetFocus());
627                 assert(id != 0);
628
629                 if (id == IDD_NEW_PASSWORD2)
630                         PostMessage(hwnd, WM_NEXTDLGCTL,
631                                 GetDlgItem(hwnd, IDD_PASSWORD_NAME), MAKELONG(1, 0));
632                 else
633                         PostMessage(hwnd, WM_NEXTDLGCTL, 0, 0);
634
635                 return TRUE;
636
637         }
638
639         return FALSE;
640
641 } /* password_command */
642
643
644 /*+
645  * Function: Process WM_INITDIALOG messages for the password dialog.
646  *      Set up all initial dialog values from the parent dialog.
647  *
648  * Parameters:
649  *      hwnd - the window recieving the message.
650  *
651  *      wparam - handle of the control for focus.
652  *
653  *      lparam - lparam from dialog box call.
654  *
655  * Returns: TRUE if we didn't set the focus here,
656  *      FALSE if we did.
657  */
658 static BOOL
659 password_initdialog (
660         HWND hwnd,
661         WPARAM wparam,
662         LPARAM lparam)
663 {
664         char name[ANAME_SZ];
665         char realm[REALM_SZ];
666         HWND hwndparent;
667         int id;
668     #ifdef KRB4
669         char instance[INST_SZ];
670     #endif
671
672         center_dialog(hwnd);
673         set_dialog_font(hwnd, hfontdialog);
674
675         hwndparent = GetParent(hwnd);
676         assert(hwndparent != NULL);
677
678         GetDlgItemText(hwndparent, IDD_LOGIN_NAME, name, sizeof(name));
679         trim(name);
680         SetDlgItemText(hwnd, IDD_PASSWORD_NAME, name);
681
682     #ifdef KRB4
683         GetDlgItemText(hwndparent, IDD_LOGIN_INSTANCE, instance, sizeof(instance));
684             trim(instance);
685         SetDlgItemText(hwnd, IDD_PASSWORD_INSTANCE, instance);
686     #endif
687
688         GetDlgItemText(hwndparent, IDD_LOGIN_REALM, realm, sizeof(realm));
689         trim(realm);
690         SetDlgItemText(hwnd, IDD_PASSWORD_REALM, realm);
691
692         if (strlen(name) == 0)
693                 id = IDD_PASSWORD_NAME;
694         else if (strlen(realm) == 0)
695                 id = IDD_PASSWORD_REALM;
696         else
697                 id = IDD_OLD_PASSWORD;
698
699         SetFocus(GetDlgItem(hwnd, id));
700
701         return FALSE;
702
703 } /* password_initdialog */
704
705
706 /*+
707  * Function: Process dialog specific messages for the password dialog.
708  *
709  * Parameters:
710  *      hwnd - the dialog receiving the message.
711  *
712  *      message - the message to process.
713  *
714  *      wparam - wparam of the message.
715  *
716  *      lparam - lparam of the message.
717  *
718  * Returns: TRUE if message handled locally, FALSE otherwise.
719  */
720 static BOOL CALLBACK
721 password_dlg_proc (
722         HWND hwnd,
723         UINT message,
724         WPARAM wparam,
725         LPARAM lparam)
726 {
727         LRESULT rc;
728
729         switch (message) {
730
731         case WM_INITDIALOG:
732                 return password_initdialog(hwnd, wparam, lparam);
733
734         case WM_COMMAND:
735                 password_command(hwnd, wparam, lparam);
736                 return (BOOL) rc;
737
738         case WM_SETCURSOR:
739                 if (isblocking) {
740                         SetCursor(LoadCursor(NULL, IDC_WAIT));
741                         SetWindowLong(hwnd, DWL_MSGRESULT, TRUE);
742
743                         return TRUE;
744                 }
745                 break;
746         }
747
748         return FALSE;
749
750 } /* password_dlg_proc */
751
752
753 /*+
754  * Function: Display and process the password dialog.
755  *
756  * Parameters:
757  *      hwnd - the parent window for the dialog
758  *
759  * Returns: TRUE if the dialog completed successfully, FALSE otherwise.
760  */
761 static BOOL
762 password_dialog (
763         HWND hwnd)
764 {
765         DLGPROC dlgproc;
766         int rc;
767
768         dlgproc = (FARPROC) MakeProcInstance(password_dlg_proc, hinstance);
769         assert(dlgproc != NULL);
770
771         if (dlgproc == NULL)
772                 return FALSE;
773
774         rc = DialogBox(hinstance, MAKEINTRESOURCE(ID_PASSWORD), hwnd, dlgproc);
775         assert(rc != -1);
776
777         FreeProcInstance((FARPROC) dlgproc);
778
779         return rc == IDOK;
780
781 } /* password_dialog */
782
783
784 /*+
785  * Function: Process WM_INITDIALOG messages for the options dialog.
786  *      Set up all initial dialog values from the KERBEROS_INI file.
787  *
788  * Parameters:
789  *      hwnd - the window recieving the message.
790  *
791  *      wparam - handle of the control for focus.
792  *
793  *      lparam - lparam from dialog box call.
794  *
795  * Returns: TRUE if we didn't set the focus here,
796  *      FALSE if we did.
797  */
798 static LONG
799 opts_initdialog (
800         HWND hwnd,
801         WPARAM wparam,
802         LPARAM lparam)
803 {
804         char defname[FILENAME_MAX];
805     char newname[FILENAME_MAX];
806         UINT rc;
807         int lifetime;
808
809         center_dialog(hwnd);
810         set_dialog_font(hwnd, hfontdialog);
811
812 /* krb.conf file */
813         rc = GetWindowsDirectory(defname, sizeof(defname));
814         assert(rc > 0);
815
816         strcat(defname, "\\");
817         strcat(defname, DEF_KRB_CONF);
818         GetPrivateProfileString(INI_FILES, INI_KRB_CONF, defname,
819                 newname, sizeof(newname), KERBEROS_INI);
820         _strupr(newname);
821         SetDlgItemText(hwnd, IDD_CONF, newname);
822
823 /* krb.realms file */
824         rc = GetWindowsDirectory(defname, sizeof(defname));
825         assert(rc > 0);
826
827         strcat(defname, "\\");
828         strcat(defname, DEF_KRB_REALMS);
829         GetPrivateProfileString(INI_FILES, INI_KRB_REALMS, defname,
830                 newname, sizeof(newname), KERBEROS_INI);
831         _strupr(newname);
832         SetDlgItemText(hwnd, IDD_REALMS, newname);
833
834 /* Credential cache file */
835     #ifdef KRB5
836         rc = GetWindowsDirectory(defname, sizeof(defname));
837         assert(rc > 0);
838
839         strcat(defname, "\\");
840         strcat(defname, "krb5cc");
841         GetPrivateProfileString(INI_FILES, INI_KRB_CCACHE, defname,
842                 ccname, sizeof(ccname), KERBEROS_INI);
843         _strupr(ccname);
844         SetDlgItemText(hwnd, IDD_CCACHE, ccname);
845     #endif /* KRB5 */
846
847 /* Ticket duration */
848         lifetime = GetPrivateProfileInt(INI_OPTIONS, INI_DURATION,
849                 DEFAULT_TKT_LIFE * 5, KERBEROS_INI);
850         SetDlgItemInt(hwnd, IDD_LIFETIME, lifetime, FALSE);
851
852 /* Expiration action */
853         GetPrivateProfileString(INI_EXPIRATION, INI_ALERT, "No",
854                 defname, sizeof(defname), KERBEROS_INI);
855         alert = _stricmp(defname, "Yes") == 0;
856         SendDlgItemMessage(hwnd, IDD_ALERT, BM_SETCHECK, alert, 0);
857         GetPrivateProfileString(INI_EXPIRATION, INI_BEEP, "No",
858                 defname, sizeof(defname), KERBEROS_INI);
859         beep = _stricmp(defname, "Yes") == 0;
860         SendDlgItemMessage(hwnd, IDD_BEEP, BM_SETCHECK, beep, 0);
861
862         return TRUE;
863
864 } /* opts_initdialog */
865
866
867 /*+
868  * Function: Process WM_COMMAND messages for the options dialog.
869  *
870  * Parameters:
871  *      hwnd - the window recieving the message.
872  *
873  *      wparam - id of the command item
874  *
875  *      lparam - LOWORD=hwnd of control, HIWORD=notification message.
876  *
877  * Returns: TRUE if initialized sucessfully, false otherwise.
878  */
879 static LONG
880 opts_command (
881         HWND hwnd,
882         WPARAM wparam,
883         LPARAM lparam)
884 {
885         char defname[FILENAME_MAX];
886         char newname[FILENAME_MAX];
887         char *p;
888         BOOL b;
889         int lifetime;
890         int rc;
891
892         switch (wparam) {
893         case IDOK:
894 /* Ticket duration */
895                 lifetime = GetDlgItemInt(hwnd, IDD_LIFETIME, &b, FALSE);
896
897                 if (!b) {
898                         MessageBox(hwnd, "Lifetime must be a number!", "", MB_OK | MB_ICONEXCLAMATION);
899                         return TRUE;
900                 }
901
902                 _itoa(lifetime, defname, 10);
903                 b = WritePrivateProfileString(INI_OPTIONS, INI_DURATION, defname, KERBEROS_INI);
904                 assert(b);
905
906 /* krb.conf file */
907                 GetDlgItemText(hwnd, IDD_CONF, newname, sizeof(newname));
908                 trim(newname);
909                 rc = GetWindowsDirectory(defname, sizeof(defname));
910                 assert(rc > 0);
911
912                 strcat(defname, "\\");
913                 strcat(defname, DEF_KRB_CONF);
914                 if (_stricmp(newname, defname) == 0 || !newname[0])
915                         p = NULL;
916                 else
917                         p = newname;
918                 b = WritePrivateProfileString(INI_FILES, INI_KRB_CONF, p, KERBEROS_INI);
919                 assert(b);
920
921 /* krb.realms file */
922                 GetDlgItemText(hwnd, IDD_REALMS, newname, sizeof(newname));
923                 trim(newname);
924                 rc = GetWindowsDirectory(defname, sizeof(defname));
925                 assert(rc > 0);
926
927                 strcat(defname, "\\");
928                 strcat(defname, DEF_KRB_REALMS);
929                 if (_stricmp(newname, defname) == 0 || !newname[0])
930                         p = NULL;
931                 else
932                         p = newname;
933                 b = WritePrivateProfileString(INI_FILES, INI_KRB_REALMS, p, KERBEROS_INI);
934                 assert(b);
935
936 /* Credential cache file */
937         #ifdef KRB5
938                 GetDlgItemText(hwnd, IDD_CCACHE, newname, sizeof(newname));
939                 trim(newname);
940                 rc = GetWindowsDirectory(defname, sizeof(defname));
941                 assert(rc > 0);
942
943                 strcat(defname, "\\");
944                 strcat(defname, "krb5cc");
945             if (*newname == '\0')
946                 strcpy (newname, defname);
947                 if (_stricmp(newname, defname) == 0 || *newname == '\0')
948                         p = NULL;
949                 else
950                         p = newname;
951                 b = WritePrivateProfileString(INI_FILES, INI_KRB_CCACHE, p, KERBEROS_INI);
952                 assert(b);
953
954             if (strcmp (ccname, newname)) {     // Did we change ccache file?
955                 krb5_error_code code;
956                 krb5_ccache cctemp;
957
958                 code = k5_init_ccache (&cctemp);
959                 if (code) {                     // Problem opening new one?
960                     com_err (NULL, code, 
961                         "while changing ccache.\r\nRestoring old ccache.");
962                         b = WritePrivateProfileString(INI_FILES, INI_KRB_CCACHE,
963                         ccname, KERBEROS_INI);
964                 } else {
965                     code = krb5_cc_close (k5_context, k5_ccache);
966                     k5_ccache = cctemp;         // Copy new into old
967                     if (k5_name_from_ccache (k5_ccache)) {
968                         kwin_init_name (GetParent(hwnd), "");
969                                 kwin_set_default_focus(GetParent(hwnd));
970                     }
971                         ticket_init_list (GetDlgItem (GetParent(hwnd),
972                         IDD_TICKET_LIST));
973                 }
974             }
975
976         #endif /* KRB5 */
977
978 /* Expiration action */
979                 alert = (BOOL) SendDlgItemMessage(hwnd, IDD_ALERT, BM_GETCHECK, 0, 0);
980                 p = (alert) ? "Yes" : "No";
981                 b = WritePrivateProfileString(INI_EXPIRATION, INI_ALERT, p, KERBEROS_INI);
982                 assert(b);
983
984                 beep = (BOOL) SendDlgItemMessage(hwnd, IDD_BEEP, BM_GETCHECK, 0, 0);
985                 p = (beep) ? "Yes" : "No";
986                 b = WritePrivateProfileString(INI_EXPIRATION, INI_BEEP, p, KERBEROS_INI);
987                 assert(b);
988
989                 EndDialog(hwnd, IDOK);
990
991                 return TRUE;
992
993         case IDCANCEL:
994                 EndDialog(hwnd, IDCANCEL);
995
996                 return TRUE;
997         }
998
999         return FALSE;
1000
1001 } /* opts_command */
1002
1003
1004 /*+
1005  * Function: Process dialog specific messages for the opts dialog.
1006  *
1007  * Parameters:
1008  *      hwnd - the dialog receiving the message.
1009  *
1010  *      message - the message to process.
1011  *
1012  *      wparam - wparam of the message.
1013  *
1014  *      lparam - lparam of the message.
1015  *
1016  * Returns: TRUE if message handled locally, FALSE otherwise.
1017  */
1018 static BOOL CALLBACK
1019 opts_dlg_proc (
1020         HWND hwnd,
1021         UINT message,
1022         WPARAM wparam,
1023         LPARAM lparam)
1024 {
1025         LRESULT rc;
1026
1027         switch (message) {
1028
1029         case WM_INITDIALOG:
1030                 rc = opts_initdialog(hwnd, wparam, lparam);
1031
1032                 return (BOOL) rc;
1033
1034         case WM_COMMAND:
1035                 rc = opts_command(hwnd, wparam, lparam);
1036
1037                 return (BOOL) rc;
1038         }
1039
1040         return FALSE;
1041
1042 } /* opts_dlg_proc */
1043
1044
1045 /*+
1046  * Function: Display and process the options dialog.
1047  *
1048  * Parameters:
1049  *      hwnd - the parent window for the dialog
1050  *
1051  * Returns: TRUE if the dialog completed successfully, FALSE otherwise.
1052  */
1053 static BOOL
1054 opts_dialog (
1055         HWND hwnd)
1056 {
1057         DLGPROC dlgproc;
1058         int rc;
1059
1060         dlgproc = (FARPROC) MakeProcInstance(opts_dlg_proc, hinstance);
1061         assert(dlgproc != NULL);
1062
1063         if (dlgproc == NULL)
1064                 return FALSE;
1065
1066         rc = DialogBox(hinstance, MAKEINTRESOURCE(ID_OPTS), hwnd, dlgproc);
1067         assert(rc != -1);
1068
1069         FreeProcInstance((FARPROC) dlgproc);
1070
1071         return rc == IDOK;
1072
1073 } /* opts_dialog */
1074
1075
1076 /*+
1077  * Function: Save most recent login triplets for placement on the
1078  *      bottom of the file menu.
1079  *
1080  * Parameters:
1081  *      hwnd - the handle of the window containing the menu to edit.
1082  *
1083  *      name - A login name to save in the recent login list
1084  *
1085  *      instance - An instance to save in the recent login list
1086  *
1087  *      realm - A realm to save in the recent login list
1088  */
1089 static void
1090 kwin_push_login (
1091         HWND hwnd,
1092         char *name,
1093         char *instance,
1094         char *realm)
1095 {
1096         HMENU hmenu;
1097         int i;
1098         int id;
1099         int ctitems;
1100         char fullname[MAX_K_NAME_SZ + 3];
1101         char menuitem[MAX_K_NAME_SZ + 3];
1102         BOOL rc;
1103
1104         strcpy(fullname, "&x ");
1105         strcat(fullname, name);
1106     strcat(fullname, ".");
1107     strcat(fullname, instance);
1108         strcat(fullname, "@");
1109         strcat(fullname, realm);
1110
1111         hmenu = GetMenu(hwnd);
1112         assert(hmenu != NULL);
1113
1114         hmenu = GetSubMenu(hmenu, 0);
1115         assert(hmenu != NULL);
1116
1117         ctitems = GetMenuItemCount(hmenu);
1118         assert(ctitems >= FILE_MENU_ITEMS);
1119
1120         if (ctitems == FILE_MENU_ITEMS) {
1121                 rc = AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
1122                 assert(rc);
1123
1124                 ctitems++;
1125         }
1126
1127         for (i = FILE_MENU_ITEMS + 1; i < ctitems; i++) {
1128                 GetMenuString(hmenu, i, menuitem, sizeof(menuitem), MF_BYPOSITION);
1129
1130                 if (strcmp(&fullname[3], &menuitem[3]) == 0) {
1131                         rc = RemoveMenu(hmenu, i, MF_BYPOSITION);
1132                         assert(rc);
1133
1134                         ctitems--;
1135
1136                         break;
1137                 }
1138         }
1139
1140         rc = InsertMenu(hmenu, FILE_MENU_ITEMS + 1, MF_BYPOSITION, 1, fullname);
1141         assert(rc);
1142
1143         ctitems++;
1144         if (ctitems - FILE_MENU_ITEMS - 1 > FILE_MENU_MAX_LOGINS) {
1145                 RemoveMenu(hmenu, ctitems - 1, MF_BYPOSITION);
1146
1147                 ctitems--;
1148         }
1149
1150         id = 0;
1151         for (i = FILE_MENU_ITEMS + 1; i < ctitems; i++) {
1152                 GetMenuString(hmenu, i, menuitem, sizeof(menuitem), MF_BYPOSITION);
1153
1154                 rc = RemoveMenu(hmenu, i, MF_BYPOSITION);
1155                 assert(rc);
1156
1157                 menuitem[1] = '1' + id;
1158                 rc = InsertMenu(hmenu, i, MF_BYPOSITION, IDM_FIRST_LOGIN + id, menuitem);
1159                 assert(rc);
1160
1161                 id++;
1162         }
1163
1164 } /* kwin_push_login */
1165
1166
1167 /*+
1168  * Function: Initialize the logins on the file menu form the KERBEROS.INI
1169  *      file.
1170  *
1171  * Parameters:
1172  *      hwnd - handle of the dialog containing the file menu.
1173  */
1174 static void
1175 kwin_init_file_menu (
1176         HWND hwnd)
1177 {
1178         HMENU hmenu;
1179         int i;
1180         char login[sizeof(INI_LOGIN)+1];
1181         char menuitem[MAX_K_NAME_SZ + 3];
1182         int id;
1183         BOOL rc;
1184
1185         hmenu = GetMenu(hwnd);
1186         assert(hmenu != NULL);
1187
1188         hmenu = GetSubMenu(hmenu, 0);
1189         assert(hmenu != NULL);
1190
1191         strcpy(login, INI_LOGIN);
1192         id = 0;
1193         for (i = 0; i < FILE_MENU_MAX_LOGINS; i++) {
1194                 login[sizeof(INI_LOGIN) - 1] = '1' + i;
1195                 login[sizeof(INI_LOGIN)] = 0;
1196                 GetPrivateProfileString(INI_RECENT_LOGINS, login, "",
1197                         &menuitem[3], sizeof(menuitem) - 3, KERBEROS_INI);
1198                 if (!menuitem[3])
1199                         continue;
1200
1201                 menuitem[0] = '&';
1202                 menuitem[1] = '1' + id;
1203                 menuitem[2] = ' ';
1204
1205                 if (id == 0) {
1206                         rc = AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
1207                         assert(rc);
1208                 }
1209                 AppendMenu(hmenu, MF_STRING, IDM_FIRST_LOGIN + id, menuitem);
1210
1211                 id++;
1212         }
1213
1214 } /* kwin_init_file_menu */
1215
1216
1217 /*+
1218  * Function: Save the items on the file menu in the KERBEROS.INI file.
1219  *
1220  * Parameters:
1221  *      hwnd - handle of the dialog containing the file menu.
1222  */
1223 static void
1224 kwin_save_file_menu (
1225         HWND hwnd)
1226 {
1227         HMENU hmenu;
1228         int i;
1229         int id;
1230         int ctitems;
1231         char menuitem[MAX_K_NAME_SZ + 3];
1232         char login[sizeof(INI_LOGIN)+1];
1233         BOOL rc;
1234
1235         hmenu = GetMenu(hwnd);
1236         assert(hmenu != NULL);
1237
1238         hmenu = GetSubMenu(hmenu, 0);
1239         assert(hmenu != NULL);
1240
1241         strcpy(login, INI_LOGIN);
1242         ctitems = GetMenuItemCount(hmenu);
1243         assert(ctitems >= FILE_MENU_ITEMS);
1244
1245         id = 0;
1246         for (i = FILE_MENU_ITEMS + 1; i < ctitems; i++) {
1247                 GetMenuString(hmenu, i, menuitem, sizeof(menuitem), MF_BYPOSITION);
1248                 login[sizeof(INI_LOGIN) - 1] = '1' + id;
1249                 login[sizeof(INI_LOGIN)] = 0;
1250
1251                 rc = WritePrivateProfileString(INI_RECENT_LOGINS, login, &menuitem[3], KERBEROS_INI);
1252                 assert(rc);
1253
1254                 id++;
1255         }
1256
1257 } /* kwin_save_file_menu */
1258
1259
1260
1261 /*+
1262  * Function: Given an expiration time, choose an appropriate
1263  *      icon to display.
1264  *
1265  * Parameters:
1266  *      expiration time of expiration in time() compatible units
1267  *
1268  * Returns: Handle of icon to display
1269  */
1270 HICON
1271 kwin_get_icon (
1272         time_t expiration)
1273 {
1274         int ixicon;
1275         time_t dt;
1276
1277         dt = expiration - time(NULL);
1278         dt = dt / 60;                   /* convert to minutes */
1279         if (dt <= 0)
1280                 ixicon = IDI_EXPIRED - IDI_FIRST_CLOCK;
1281         else if (dt > 60)
1282                 ixicon = IDI_TICKET - IDI_FIRST_CLOCK;
1283         else
1284                 ixicon = (int) (dt / 5);
1285
1286         return kwin_icons[ixicon];
1287
1288 } /* kwin_get_icon */
1289
1290
1291 /*+
1292  * Function: Intialize name fields in the Kerberos dialog.
1293  *
1294  * Parameters:
1295  *      hwnd - the window recieving the message.
1296  *
1297  *      fullname - the full kerberos name to initialize with
1298  */
1299 static void
1300 kwin_init_name (
1301         HWND hwnd,
1302         char *fullname)
1303 {
1304     char name[ANAME_SZ];
1305     char instance[INST_SZ];
1306     char realm[REALM_SZ];
1307         int krc;
1308
1309         if (fullname == NULL || fullname[0] == 0) {
1310                 #ifdef KRB4
1311                         strcpy(name, krb_get_default_user());
1312             GetPrivateProfileString(INI_DEFAULTS, INI_INSTANCE, "",
1313                 instance, sizeof(instance), KERBEROS_INI);
1314                         krc = krb_get_lrealm(realm, 1);
1315                         if (krc != KSUCCESS)
1316                                 realm[0] = 0;
1317                 GetPrivateProfileString(INI_DEFAULTS, INI_REALM, realm,
1318                         realm, sizeof(realm), KERBEROS_INI);
1319                 #endif
1320
1321
1322                 #ifdef KRB5
1323         {
1324             krb5_error_code code;
1325             char *ptr;
1326
1327             GetPrivateProfileString (INI_DEFAULTS, INI_USER, "",
1328                 name, sizeof(name), KERBEROS_INI);
1329
1330             *realm = '\0';
1331             code = krb5_get_default_realm (k5_context, &ptr);
1332             if (! code) {
1333                 strcpy (realm, ptr);
1334                 free (ptr);
1335             }
1336                 GetPrivateProfileString(INI_DEFAULTS, INI_REALM, realm,
1337                         realm, sizeof(realm), KERBEROS_INI);
1338         }
1339                 #endif
1340
1341         } else {
1342                 #ifdef KRB4
1343                         kname_parse(name, instance, realm, fullname);
1344                 SetDlgItemText(hwnd, IDD_LOGIN_INSTANCE, instance);
1345                 #endif
1346
1347                 #ifdef KRB5
1348                         krc = k5_kname_parse(name, realm, fullname);
1349             *instance = '\0';
1350                 #endif
1351         }
1352
1353         SetDlgItemText(hwnd, IDD_LOGIN_NAME, name);
1354         SetDlgItemText(hwnd, IDD_LOGIN_REALM, realm);
1355
1356 } /* kwin_init_name */
1357
1358
1359 /*+
1360  * Function: Set the focus to the name control if no name
1361  *      exists, the realm control if no realm exists or the
1362  *      password control.  Uses PostMessage not SetFocus.
1363  *
1364  * Parameters:
1365  *      hwnd - the Window handle of the parent.
1366  */
1367 void
1368 kwin_set_default_focus (
1369         HWND hwnd)
1370 {
1371         char name[ANAME_SZ];
1372         char realm[REALM_SZ];
1373         HWND hwnditem;
1374
1375         GetDlgItemText(hwnd, IDD_LOGIN_NAME, name, sizeof(name));
1376
1377         trim(name);
1378         if (strlen(name) <= 0)
1379                 hwnditem = GetDlgItem(hwnd, IDD_LOGIN_NAME);
1380         else {
1381                 GetDlgItemText(hwnd, IDD_LOGIN_REALM, realm, sizeof(realm));
1382                 trim(realm);
1383
1384                 if (strlen(realm) <= 0)
1385                         hwnditem = GetDlgItem(hwnd, IDD_LOGIN_REALM);
1386                 else
1387                         hwnditem = GetDlgItem(hwnd, IDD_LOGIN_PASSWORD);
1388         }
1389
1390         PostMessage(hwnd, WM_NEXTDLGCTL, hwnditem, MAKELONG(1, 0));
1391
1392 } /* kwin_set_default_focus */
1393
1394
1395 /*+
1396  * Function: Save the values which live in the KERBEROS.INI file.
1397  *
1398  * Parameters:
1399  *      hwnd - the window handle of the dialog containing fields to
1400  *              be saved
1401  */
1402 static void
1403 kwin_save_name (
1404         HWND hwnd)
1405 {
1406         char name[ANAME_SZ];
1407         char instance[INST_SZ];
1408         char realm[REALM_SZ];
1409
1410         GetDlgItemText(hwnd, IDD_LOGIN_NAME, name, sizeof(name));
1411         trim(name);
1412
1413         #ifdef KRB4
1414                 krb_set_default_user(name);
1415         GetDlgItemText(hwnd, IDD_LOGIN_INSTANCE, instance, sizeof(instance));
1416         trim(instance);
1417         WritePrivateProfileString(INI_DEFAULTS, INI_INSTANCE, instance, KERBEROS_INI);
1418         #endif
1419
1420         #ifdef KRB5
1421         WritePrivateProfileString(INI_DEFAULTS, INI_USER, name, KERBEROS_INI);
1422         *instance = '\0';
1423         #endif
1424
1425         GetDlgItemText(hwnd, IDD_LOGIN_REALM, realm, sizeof(realm));
1426         trim(realm);
1427         WritePrivateProfileString(INI_DEFAULTS, INI_REALM, realm, KERBEROS_INI);
1428
1429         kwin_push_login(hwnd, name, instance, realm);
1430
1431 } /* kwin_save_name */
1432
1433
1434 /*+
1435  * Function: Process WM_INITDIALOG messages.  Set the fonts
1436  *      for all items on the dialog and populate the ticket list.
1437  *      Also set the default values for user, instance and realm.
1438  *
1439  * Parameters:
1440  *      hwnd - the window recieving the message.
1441  *
1442  *      wparam - handle of the control for focus.
1443  *
1444  *      lparam - lparam from dialog box call.
1445  *
1446  * Returns: TRUE if we didn't set the focus here,
1447  *      FALSE if we did.
1448  */
1449 static BOOL
1450 kwin_initdialog (
1451         HWND hwnd,
1452         WPARAM wparam,
1453         LPARAM lparam)
1454 {
1455         LOGFONT lf;
1456         HDC hdc;
1457         char name[ANAME_SZ];
1458
1459         position_dialog(hwnd);
1460         ticket_init_list(GetDlgItem(hwnd, IDD_TICKET_LIST));
1461         kwin_init_file_menu(hwnd);
1462         kwin_init_name(hwnd, (char *) lparam);
1463         hdc = GetDC(NULL);
1464         assert(hdc != NULL);
1465
1466         memset(&lf, 0, sizeof(lf));
1467         lf.lfHeight = -MulDiv(9, GetDeviceCaps(hdc, LOGPIXELSY), 72);
1468         strcpy(lf.lfFaceName, "Arial");
1469         hfontdialog = CreateFontIndirect(&lf);
1470         assert(hfontdialog != NULL);
1471
1472         if (hfontdialog == NULL) {
1473                 ReleaseDC(NULL, hdc);
1474
1475                 return TRUE;
1476         }
1477
1478         lf.lfHeight = -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72);
1479         hfonticon = CreateFontIndirect(&lf);
1480         assert(hfonticon != NULL);
1481
1482         if (hfonticon == NULL) {
1483                 ReleaseDC(NULL, hdc);
1484
1485                 return TRUE;
1486         }
1487
1488         ReleaseDC(NULL, hdc);
1489
1490         set_dialog_font(hwnd, hfontdialog);
1491         GetDlgItemText(hwnd, IDD_LOGIN_NAME, name, sizeof(name));
1492         trim(name);
1493
1494         if (strlen(name) > 0)
1495                 SetFocus(GetDlgItem(hwnd, IDD_LOGIN_PASSWORD));
1496         else
1497                 SetFocus(GetDlgItem(hwnd, IDD_LOGIN_NAME));
1498
1499         ShowWindow(hwnd, dlgncmdshow);
1500         kwin_timer_id = SetTimer(hwnd, 1, KWIN_UPDATE_PERIOD, NULL);
1501         assert(kwin_timer_id != 0);
1502
1503         return FALSE;
1504
1505 } /* kwin_initdialog */
1506
1507
1508 /*+
1509  * Function: Process WM_DESTROY messages.  Delete the font
1510  *      created for use by the controls.
1511  *
1512  * Parameters:
1513  *      hwnd - the window recieving the message.
1514  *
1515  *      wparam - none
1516  *
1517  *      lparam - none
1518  *
1519  * Returns: 0
1520  */
1521 static LONG
1522 kwin_destroy (
1523         HWND hwnd,
1524         WPARAM wparam,
1525         LPARAM lparam)
1526 {
1527         char position[256];
1528         RECT r;
1529         BOOL b;
1530
1531         ticket_destroy(GetDlgItem(hwnd, IDD_TICKET_LIST));
1532
1533         if (hfontdialog != NULL)
1534                 DeleteObject(hfontdialog);
1535
1536         if (hfonticon != NULL)
1537                 DeleteObject(hfonticon);
1538
1539         kwin_save_file_menu(hwnd);
1540         GetWindowRect(hwnd, &r);
1541         sprintf(position, "[%d,%d,%d,%d]", r.left, r.top,
1542                 r.right - r.left, r.bottom - r.top);
1543         b = WritePrivateProfileString(INI_DEFAULTS, INI_POSITION, position, KERBEROS_INI);
1544         assert(b);
1545
1546         KillTimer(hwnd, kwin_timer_id);
1547
1548         return 0;
1549
1550 } /* kwin_destroy */
1551
1552
1553 /*+
1554  * Function: Retrievs item WindowRect in hwnd client
1555  *      coordiate system.
1556  *
1557  * Parameters:
1558  *      hwnditem - the item to retrieve
1559  *
1560  *      item - dialog in which into which to translate
1561  *
1562  *      r - rectangle returned
1563  */
1564 static void
1565 windowrect (
1566         HWND hwnditem,
1567         HWND hwnd,
1568         RECT *r)
1569 {
1570         GetWindowRect(hwnditem, r);
1571         ScreenToClient(hwnd, (LPPOINT) &(r->left));
1572         ScreenToClient(hwnd, (LPPOINT) &(r->right));
1573
1574 } /* windowrect */
1575
1576
1577 /*+
1578  * Function: Process WM_SIZE messages.  Resize the
1579  *      list and position the buttons attractively.
1580  *
1581  * Parameters:
1582  *      hwnd - the window receiving the message.
1583  *
1584  *      wparam - type of resize occuring
1585  *
1586  *      lparam - LOWORD=width of client area,
1587  *              HIWORD=height of client area.
1588  *
1589  * Returns: 0
1590  */
1591 static LONG
1592 kwin_size (
1593         HWND hwnd,
1594         WPARAM wparam,
1595         LPARAM lparam)
1596 {
1597         #define listgap 8
1598         RECT r;
1599         RECT rdlg;
1600         int hmargin, vmargin;
1601         HWND hwnditem;
1602         int cx, cy;
1603         int cxdlg, cydlg;
1604         int i;
1605         int titlebottom;
1606         int editbottom;
1607         int listbottom;
1608         int gap;
1609         int left;
1610         int titleleft[IDD_MAX_TITLE - IDD_MIN_TITLE + 1];
1611
1612         if (wparam == SIZE_MINIMIZED)
1613                 return 0;
1614
1615         GetClientRect(hwnd, &rdlg);
1616         cxdlg = LOWORD(lparam);
1617         cydlg = HIWORD(lparam);
1618
1619         /*
1620          * The ticket list title
1621          */
1622         hwnditem = GetDlgItem(hwnd, IDD_TICKET_LIST_TITLE);
1623
1624         if (hwnditem == NULL)
1625                 return 0;
1626
1627         windowrect(hwnditem, hwnd, &r);
1628         hmargin = r.left;
1629         vmargin = r.top;
1630         cx = cxdlg - 2 * hmargin;
1631         cy = r.bottom - r.top;
1632         MoveWindow(hwnditem, r.left, r.top, cx, cy, TRUE);
1633
1634         /*
1635          * The buttons
1636          */
1637         cx = 0;
1638
1639         for (i = IDD_MIN_BUTTON; i <= IDD_MAX_BUTTON; i++) {
1640                 hwnditem = GetDlgItem(hwnd, i);
1641                 windowrect(hwnditem, hwnd, &r);
1642                 if (i == IDD_MIN_BUTTON)
1643                         hmargin = r.left;
1644
1645                 cx += r.right - r.left;
1646         }
1647
1648         gap = (cxdlg - 2 * hmargin - cx) / (IDD_MAX_BUTTON - IDD_MIN_BUTTON);
1649         left = hmargin;
1650         for (i = IDD_MIN_BUTTON; i <= IDD_MAX_BUTTON; i++) {
1651                 hwnditem = GetDlgItem(hwnd, i);
1652                 windowrect(hwnditem, hwnd, &r);
1653                 editbottom = -r.top;
1654                 cx = r.right - r.left;
1655                 cy = r.bottom - r.top;
1656                 r.top = rdlg.bottom - vmargin - cy;
1657                 MoveWindow(hwnditem, left, r.top, cx, cy, TRUE);
1658
1659                 left += cx + gap;
1660         }
1661
1662         /*
1663          * Edit fields: stretch boxes, keeping the gap between boxes equal to
1664      * what it was on entry.
1665          */
1666         editbottom += r.top;
1667
1668     hwnditem = GetDlgItem(hwnd, IDD_MIN_EDIT);
1669     windowrect(hwnditem, hwnd, &r);
1670         gap = r.right;
1671         hmargin = r.left;
1672         editbottom += r.bottom;
1673         titlebottom = -r.top;
1674
1675     hwnditem = GetDlgItem(hwnd, IDD_MIN_EDIT + 1);
1676     windowrect(hwnditem, hwnd, &r);
1677         gap = r.left - gap;
1678
1679         cx = cxdlg - 2 * hmargin - (IDD_MAX_EDIT - IDD_MIN_EDIT) * gap;
1680         cx = cx / (IDD_MAX_EDIT - IDD_MIN_EDIT + 1);
1681         left = hmargin;
1682
1683         for (i = IDD_MIN_EDIT; i <= IDD_MAX_EDIT; i++) {
1684                 hwnditem = GetDlgItem(hwnd, i);
1685                 windowrect(hwnditem, hwnd, &r);
1686                 cy = r.bottom - r.top;
1687                 r.top = editbottom - cy;
1688                 MoveWindow(hwnditem, left, r.top, cx, cy, TRUE);
1689                 titleleft[i-IDD_MIN_EDIT] = left;
1690
1691                 left += cx + gap;
1692         }
1693
1694         /*
1695          * Edit field titles
1696          */
1697         titlebottom += r.top;
1698         windowrect(GetDlgItem(hwnd, IDD_MIN_TITLE), hwnd, &r);
1699         titlebottom += r.bottom;
1700         listbottom = -r.top;
1701
1702         for (i = IDD_MIN_TITLE; i <= IDD_MAX_TITLE; i++) {
1703                 hwnditem = GetDlgItem(hwnd, i);
1704                 windowrect(hwnditem, hwnd, &r);
1705                 cx = r.right - r.left;
1706                 cy = r.bottom - r.top;
1707                 r.top = titlebottom - cy;
1708                 MoveWindow(hwnditem, titleleft[i-IDD_MIN_TITLE], r.top, cx, cy, TRUE);
1709         }
1710
1711         /*
1712          * The list
1713          */
1714         listbottom = r.top - listgap;
1715         hwnditem = GetDlgItem(hwnd, IDD_TICKET_LIST);
1716         windowrect(hwnditem, hwnd, &r);
1717         hmargin = r.left;
1718         cx = cxdlg - 2 * hmargin;
1719         cy = listbottom - r.top;
1720         MoveWindow(hwnditem, r.left, r.top, cx, cy, TRUE);
1721
1722         return 0;
1723
1724 } /* kwin_size */
1725
1726
1727 /*+
1728  * Function: Process WM_GETMINMAXINFO messages
1729  *
1730  * Parameters:
1731  *      hwnd - the window recieving the message.
1732  *
1733  *      wparam - none.
1734  *
1735  *      lparam - LPMINMAXINFO
1736  *
1737  * Returns: 0
1738  */
1739 static LONG
1740 kwin_getminmaxinfo (
1741         HWND hwnd,
1742         WPARAM wparam,
1743         LPARAM lparam)
1744 {
1745         MINMAXINFO *lpmmi;
1746
1747         lpmmi = (MINMAXINFO *) lparam;
1748         lpmmi->ptMinTrackSize.x = (KWIN_MIN_WIDTH * LOWORD(GetDialogBaseUnits())) / 4;
1749         lpmmi->ptMinTrackSize.y = (KWIN_MIN_HEIGHT * HIWORD(GetDialogBaseUnits())) / 8;
1750
1751         return 0;
1752
1753 } /*  kwin_getminmaxinfo */
1754
1755
1756 /*+
1757  * Function: Process WM_TIMER messages
1758  *
1759  * Parameters:
1760  *      hwnd - the window recieving the message.
1761  *
1762  *      wparam - the timer id.
1763  * 
1764  *      lparam - timer callback proceedure
1765  *
1766  * Returns: 0
1767  */
1768 static LONG
1769 kwin_timer (
1770         HWND hwnd,
1771         WPARAM wparam,
1772         LPARAM lparam)
1773 {
1774         HWND hwndfocus;
1775         time_t t;
1776         time_t expiration;
1777         BOOL expired;
1778     #ifdef KRB4
1779         CREDENTIALS c;
1780             int ncred;
1781             int i;
1782             char service[ANAME_SZ];
1783             char instance[INST_SZ];
1784             char realm[REALM_SZ];
1785     #endif
1786     #ifdef KRB5
1787         krb5_error_code code;
1788         krb5_cc_cursor cursor;
1789         krb5_creds cred;
1790         int n;
1791         char *s;
1792     #endif
1793
1794         if (wparam != 1)
1795                 return DefDlgProc(hwnd, WM_TIMER, wparam, lparam);
1796
1797         expired = FALSE;
1798         ticket_init_list(GetDlgItem(hwnd, IDD_TICKET_LIST));
1799
1800         if (alerted) {
1801                 if (IsIconic(hwnd))
1802                         InvalidateRect(hwnd, NULL, TRUE);
1803
1804                 return 0;
1805         }
1806
1807     #ifdef KRB4
1808             ncred = krb_get_num_cred();
1809             for (i = 1; i <= ncred; i++) {
1810                     krb_get_nth_cred(service, instance, realm, i);
1811
1812                     if (_stricmp(service, "krbtgt") == 0) {
1813                 /* Warn if ticket will expire w/i TIME_BUFFER seconds */
1814                             krb_get_cred(service, instance, realm, &c);
1815                             expiration = c.issue_date + (long) c.lifetime * 5L * 60L;
1816                             t = TIME_BUFFER + time(NULL);
1817
1818                             if (t >= expiration) {
1819                                     expired = TRUE;
1820                     /* Don't alert because of stale tickets */
1821                                     if (t >= expiration + KWIN_UPDATE_PERIOD / 1000) {
1822                                             alerted = TRUE;
1823
1824                                             if (IsIconic(hwnd))
1825                                                     InvalidateRect(hwnd, NULL, TRUE);
1826                                             return 0;
1827                                     }
1828                                     break;
1829                             }
1830                     }
1831             }
1832     #endif
1833
1834     #ifdef KRB5
1835         code = krb5_cc_start_seq_get (k5_context, k5_ccache, &cursor);
1836
1837         while (code == 0) {
1838             code = krb5_cc_next_cred(k5_context, k5_ccache, &cursor, &cred);
1839             if (code)
1840                 break;
1841             n = krb5_princ_component(k5_context, cred.server, 0)->length;
1842             s = krb5_princ_component(k5_context, cred.server, 0)->data;
1843             if (n != KRB5_TGS_NAME_SIZE)
1844                 continue;
1845             if (memcmp (KRB5_TGS_NAME, s, KRB5_TGS_NAME_SIZE))
1846                 continue;
1847
1848             /* Warn if ticket will expire w/i TIME_BUFFER seconds */
1849             expiration = cred.times.endtime;
1850             t = TIME_BUFFER + time(NULL);
1851
1852             if (t >= expiration) {
1853                 expired = TRUE;
1854                 /* Don't alert because of stale tickets */
1855                 if (t >= expiration + KWIN_UPDATE_PERIOD / 1000) {
1856                     alerted = TRUE;
1857
1858                     if (IsIconic(hwnd))
1859                         InvalidateRect(hwnd, NULL, TRUE);
1860                     return 0;
1861                 }
1862                 break;
1863             }
1864         }
1865         if (code == 0 || code == KRB5_CC_END)
1866             krb5_cc_end_seq_get(k5_context, k5_ccache, &cursor);
1867     
1868     #endif
1869
1870         if (!expired) {
1871                 if (IsIconic(hwnd))
1872                         InvalidateRect(hwnd, NULL, TRUE);
1873
1874                 return 0;
1875         }
1876
1877         alerted = TRUE;
1878
1879         if (beep)
1880                 MessageBeep(MB_ICONEXCLAMATION);
1881
1882         if (alert) {
1883                 if (IsIconic(hwnd)) {
1884                         hwndfocus = GetFocus();
1885                         ShowWindow(hwnd, SW_RESTORE);
1886                         SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
1887                                 SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
1888                         SetFocus(hwndfocus);
1889                 }
1890
1891                 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
1892                         SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
1893
1894                 return 0;
1895         }
1896
1897     if (IsIconic(hwnd))
1898         InvalidateRect(hwnd, NULL, TRUE);
1899
1900     return 0;
1901
1902 } /*  kwin_timer */
1903
1904
1905 /*+
1906  * Function: Process WM_COMMAND messages
1907  *
1908  * Parameters:
1909  *      hwnd - the window recieving the message.
1910  *
1911  *      wparam - id of the command item
1912  *
1913  *      lparam - LOWORD=hwnd of control, HIWORD=notification message.
1914  *
1915  * Returns: TRUE if initialized sucessfully, false otherwise.
1916  */
1917 static LONG
1918 kwin_command (
1919         HWND hwnd,
1920         WPARAM wparam,
1921         LPARAM lparam)
1922 {
1923     char name[ANAME_SZ];
1924     char realm[REALM_SZ];
1925     char password[MAX_KPW_LEN];
1926         HCURSOR hcursor;
1927         BOOL blogin;
1928         HMENU hmenu;
1929         char menuitem[MAX_K_NAME_SZ + 3];
1930         char copyright[128];
1931         int id;
1932         #ifdef KRB4
1933         char instance[INST_SZ];
1934         int lifetime;
1935                 int krc;
1936         #endif
1937         #ifdef KRB5
1938         long lifetime;
1939                 krb5_error_code code;
1940         krb5_principal principal;
1941                 krb5_creds creds;
1942                 krb5_principal server;
1943                 krb5_timestamp now;
1944         krb5_int32 sec, usec;
1945         #endif
1946
1947         #ifdef KRB4
1948                 EnableWindow(GetDlgItem(hwnd, IDD_TICKET_DELETE), krb_get_num_cred() > 0);
1949         #endif
1950
1951         #ifdef KRB5
1952                 EnableWindow(GetDlgItem(hwnd, IDD_TICKET_DELETE), k5_get_num_cred(0) > 0);
1953         #endif
1954
1955         GetDlgItemText(hwnd, IDD_LOGIN_NAME, name, sizeof(name));
1956         trim(name);
1957         blogin = strlen(name) > 0;
1958
1959         if (blogin) {
1960                 GetDlgItemText(hwnd, IDD_LOGIN_REALM, realm, sizeof(realm));
1961                 trim(realm);
1962                 blogin = strlen(realm) > 0;
1963         }
1964
1965         if (blogin) {
1966                 GetDlgItemText(hwnd, IDD_LOGIN_PASSWORD, password, sizeof(password));
1967                 blogin = strlen(password) > 0;
1968         }
1969
1970         EnableWindow(GetDlgItem(hwnd, IDD_LOGIN), blogin);
1971     id = (blogin) ? IDD_LOGIN : IDD_PASSWORD_CR2;
1972     SendMessage(hwnd, DM_SETDEFID, id, 0);
1973
1974         if (HIWORD(lparam) != BN_CLICKED && HIWORD(lparam) != 0 && HIWORD(lparam) != 1)
1975                 return FALSE;
1976
1977         if (wparam >= IDM_FIRST_LOGIN && wparam < IDM_FIRST_LOGIN + FILE_MENU_MAX_LOGINS) {
1978                 hmenu = GetMenu(hwnd);
1979                 assert(hmenu != NULL);
1980
1981                 hmenu = GetSubMenu(hmenu, 0);
1982                 assert(hmenu != NULL);
1983
1984                 if (!GetMenuString(hmenu, wparam, menuitem, sizeof(menuitem), MF_BYCOMMAND))
1985                         return TRUE;
1986
1987                 if (menuitem[0])
1988                         kwin_init_name(hwnd, &menuitem[3]);
1989
1990                 return TRUE;
1991         }
1992
1993         switch (wparam) {
1994         case IDM_EXIT:
1995                 if (isblocking)
1996                         WSACancelBlockingCall();
1997                 WinHelp(hwnd, KERBEROS_HLP, HELP_QUIT, 0);
1998                 PostQuitMessage(0);
1999
2000                 return TRUE;
2001
2002     case IDD_PASSWORD_CR2:                      // Make CR == TAB
2003                 id = GetDlgCtrlID(GetFocus());
2004                 assert(id != 0);
2005
2006                 if (id == IDD_MAX_EDIT)
2007                         PostMessage(hwnd, WM_NEXTDLGCTL,
2008                                 GetDlgItem(hwnd, IDD_MIN_EDIT), MAKELONG(1, 0));
2009                 else
2010                         PostMessage(hwnd, WM_NEXTDLGCTL, 0, 0);
2011
2012         return TRUE;
2013
2014         case IDD_LOGIN:
2015                 if (isblocking)
2016                         return TRUE;
2017
2018                 GetDlgItemText(hwnd, IDD_LOGIN_NAME, name, sizeof(name));
2019                 trim(name);
2020                 GetDlgItemText(hwnd, IDD_LOGIN_REALM, realm, sizeof(realm));
2021                 trim(realm);
2022                 GetDlgItemText(hwnd, IDD_LOGIN_PASSWORD, password, sizeof(password));
2023                 trim(password);
2024
2025         #ifdef KRB4
2026                 GetDlgItemText(hwnd, IDD_LOGIN_INSTANCE, instance, sizeof(instance));
2027                 trim(instance);
2028         #endif
2029
2030                 hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
2031                 lifetime = GetPrivateProfileInt(INI_OPTIONS, INI_DURATION,
2032                         DEFAULT_TKT_LIFE * 5, KERBEROS_INI);
2033                 start_blocking_hook(BLOCK_MAX_SEC);
2034
2035                 #ifdef KRB4
2036                         lifetime = (lifetime + 4) / 5;
2037                         krc = krb_get_pw_in_tkt(name, instance, realm, "krbtgt", realm,
2038                                 lifetime, password);
2039                 #endif
2040
2041                 #ifdef KRB5
2042             do {
2043                 principal = server = NULL;
2044                         memset(&creds, 0, sizeof(creds));
2045
2046                 sprintf (menuitem, "%s@%s", name, realm);
2047                 code = krb5_parse_name(k5_context, menuitem, &principal);
2048                 if (code) break;
2049
2050                         code = krb5_cc_initialize(k5_context, k5_ccache, principal);
2051                 if (code) break;
2052
2053                         code = krb5_build_principal_ext(k5_context, &server,
2054                                 krb5_princ_realm(k5_context, principal)->length,
2055                                 krb5_princ_realm(k5_context, principal)->data,
2056                     KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
2057                                     krb5_princ_realm(k5_context, principal)->length,
2058                                 krb5_princ_realm(k5_context, principal)->data, 0);
2059                 if (code) break;
2060
2061                         creds.client = principal;
2062                         creds.server = server;
2063
2064                 code = krb5_us_timeofday(k5_context, &sec, &usec);
2065                 if (code) break;
2066  code = krb5_timeofday(k5_context, &now);
2067  if (code) break;
2068  if (labs(now-sec) > 60*60) {            // Off by more than an hour
2069      MessageBox (NULL, "DEBUG: timeofday != us_timeofday", NULL, 0);
2070      now = sec;
2071  }
2072                 creds.times.starttime = 0;
2073                         creds.times.endtime = sec + 60L * lifetime;
2074                         creds.times.renew_till = 0;
2075
2076                         code = krb5_get_in_tkt_with_password(k5_context, 0, NULL,
2077                     NULL, NULL, password, k5_ccache, &creds, 0);
2078             } while (0);
2079
2080             if (principal)
2081                 krb5_free_principal(k5_context, principal);
2082             if (server) 
2083                         krb5_free_principal(k5_context, server);
2084
2085                 #endif  /* KRB5 */
2086
2087                 end_blocking_hook();
2088                 SetCursor(hcursor);
2089                 kwin_set_default_focus(hwnd);
2090
2091                 #ifdef KRB4
2092                         if (krc != KSUCCESS) {
2093                                 MessageBox(hwnd, krb_get_err_text(krc), "",
2094                                         MB_OK | MB_ICONEXCLAMATION);
2095
2096                                 return TRUE;
2097                         }
2098                 #endif
2099
2100                 #ifdef KRB5
2101                         if (code) {
2102                                 com_err (NULL, code, "while logging in");
2103                                 return TRUE;
2104                         }
2105                 #endif
2106
2107                 SetDlgItemText(hwnd, IDD_LOGIN_PASSWORD, "");
2108                 kwin_save_name(hwnd);
2109                 alerted = FALSE;
2110
2111                 switch (action) {
2112                 case LOGIN_AND_EXIT:
2113                         SendMessage(hwnd, WM_COMMAND, IDM_EXIT, 0);
2114                         break;
2115
2116                 case LOGIN_AND_MINIMIZE:
2117                         ShowWindow(hwnd, SW_MINIMIZE);
2118                         break;
2119                 }
2120
2121                 return TRUE;
2122
2123         case IDD_TICKET_DELETE:
2124                 if (isblocking)
2125                         return TRUE;
2126
2127                 #ifdef KRB4
2128                 krc = dest_tkt();
2129                         if (krc != KSUCCESS)
2130                                 MessageBox(hwnd, krb_get_err_text(krc), "",
2131                                         MB_OK | MB_ICONEXCLAMATION);
2132                 #endif
2133
2134                 #ifdef KRB5
2135             code = k5_dest_tkt ();
2136                 #endif
2137
2138                 kwin_set_default_focus(hwnd);
2139                 alerted = FALSE;
2140
2141                 return TRUE;
2142
2143         case IDD_CHANGE_PASSWORD:
2144                 if (isblocking)
2145                         return TRUE;
2146                 password_dialog(hwnd);
2147                 kwin_set_default_focus(hwnd);
2148
2149                 return TRUE;
2150
2151         case IDM_OPTIONS:
2152                 if (isblocking)
2153                         return TRUE;
2154                 opts_dialog(hwnd);
2155
2156                 return TRUE;
2157
2158         case IDM_HELP_INDEX:
2159                 WinHelp(hwnd, KERBEROS_HLP, HELP_INDEX, 0);
2160
2161                 return TRUE;
2162
2163         case IDM_ABOUT:
2164         ticket_init_list(GetDlgItem(hwnd, IDD_TICKET_LIST));
2165                 if (isblocking)
2166                         return TRUE;
2167
2168         #ifdef KRB4
2169                 strcpy(copyright, "        Kerberos 4 for Windows\n");
2170         #endif
2171         #ifdef KRB5
2172                 strcpy(copyright, "        Kerberos 5 for Windows\n");
2173         #endif
2174                 strcat(copyright, "\n                Version 1.00\n\n");
2175                 strcat(copyright, "          For support, contact:\n");
2176                 strcat(copyright, ORGANIZATION);
2177                 strcat(copyright, " - (415) 903-1400");
2178                 MessageBox(hwnd, copyright, "Kerberos", MB_OK);
2179
2180                 return TRUE;
2181         }
2182
2183         return FALSE;
2184
2185 } /* kwin_command */
2186
2187
2188 /*+
2189  * Function: Process WM_SYSCOMMAND messages by setting
2190  *      the focus to the password or name on restore.
2191  *
2192  * Parameters:
2193  *      hwnd - the window recieving the message.
2194  *
2195  *      wparam - the syscommand option.
2196  *
2197  *      lparam -
2198  *
2199  * Returns: 0
2200  */
2201 static LONG
2202 kwin_syscommand (
2203         HWND hwnd,
2204         WPARAM wparam,
2205         LPARAM lparam)
2206 {
2207         if ((wparam & 0xFFF0) == SC_RESTORE)
2208                 kwin_set_default_focus(hwnd);
2209
2210         if ((wparam & 0xFFF0) == SC_CLOSE) {
2211                 SendMessage(hwnd, WM_COMMAND, IDM_EXIT, 0);
2212
2213                 return 0;
2214         }
2215
2216         return DefDlgProc(hwnd, WM_SYSCOMMAND, wparam, lparam);
2217
2218 } /* kwin_syscommand */
2219
2220
2221 /*+
2222  * Function: Process WM_PAINT messages by displaying an
2223  *      informative icon when we are iconic.
2224  *
2225  * Parameters:
2226  *      hwnd - the window recieving the message.
2227  *
2228  *      wparam - none
2229  *
2230  *      lparam - none
2231  *
2232  * Returns: 0
2233  */
2234 static LONG
2235 kwin_paint (
2236         HWND hwnd,
2237         WPARAM wparam,
2238         LPARAM lparam)
2239 {
2240         HDC hdc;
2241         PAINTSTRUCT ps;
2242         HICON hicon;
2243         time_t expiration = 0;
2244         time_t dt;
2245         char buf[20];
2246         RECT r;
2247         #ifdef KRB4
2248                 int i;
2249                 int ncred;
2250                 char service[ANAME_SZ];
2251                 char instance[INST_SZ];
2252                 char realm[REALM_SZ];
2253                 CREDENTIALS c;
2254         #endif
2255         #ifdef KRB5
2256         krb5_error_code code;
2257         krb5_cc_cursor cursor;
2258         krb5_creds c;
2259         int n;
2260         char *service;
2261         #endif
2262
2263         if (!IsIconic(hwnd))
2264                 return DefDlgProc(hwnd, WM_PAINT, wparam, lparam);
2265
2266         #ifdef KRB4
2267                 ncred = krb_get_num_cred();
2268
2269                 for (i = 1; i <= ncred; i++) {
2270                         krb_get_nth_cred(service, instance, realm, i);
2271                         krb_get_cred(service, instance, realm, &c);
2272                         if (_stricmp(c.service, "krbtgt") == 0) {
2273                                 expiration = c.issue_date - kwin_get_epoch() + (long) c.lifetime * 5L * 60L;
2274                                 break;
2275                         }
2276                 }
2277         #endif
2278
2279         #ifdef KRB5
2280         code = krb5_cc_start_seq_get (k5_context, k5_ccache, &cursor);
2281
2282         while (code == 0) {
2283             code = krb5_cc_next_cred(k5_context, k5_ccache, &cursor, &c);
2284             if (code)
2285                 break;
2286             n = krb5_princ_component(k5_context, c.server, 0)->length;
2287             service = krb5_princ_component(k5_context, c.server, 0)->data;
2288             if (n != KRB5_TGS_NAME_SIZE)
2289                 continue;
2290             if (memcmp (KRB5_TGS_NAME, service, KRB5_TGS_NAME_SIZE))
2291                 continue;
2292             expiration = c.times.endtime;
2293             break;
2294                 
2295         }
2296         if (code == 0 || code == KRB5_CC_END)
2297             krb5_cc_end_seq_get(k5_context, k5_ccache, &cursor);
2298         #endif
2299
2300         hdc = BeginPaint(hwnd, &ps);
2301         GetClientRect(hwnd, &r);
2302         DefWindowProc(hwnd, WM_ICONERASEBKGND, hdc, 0);
2303
2304         if (expiration == 0) {
2305                 strcpy(buf, KWIN_DIALOG_NAME);
2306                 hicon = LoadIcon(hinstance, MAKEINTRESOURCE(IDI_KWIN));
2307         }
2308         else {
2309                 hicon = kwin_get_icon(expiration);
2310                 dt = (expiration - time(NULL)) / 60;
2311
2312                 if (dt <= 0)
2313                         sprintf(buf, "%s - %s", KWIN_DIALOG_NAME, "Expired");
2314                 else if (dt < 60) {
2315                         dt %= 60;
2316                         sprintf(buf, "%s - %ld min", KWIN_DIALOG_NAME, dt);
2317                 }
2318                 else {
2319                         dt /= 60;
2320                         sprintf(buf, "%s - %ld hr", KWIN_DIALOG_NAME, dt);
2321                 }
2322
2323                 if (dt > 1)
2324                         strcat(buf, "s");
2325         }
2326
2327         DrawIcon(hdc, r.left, r.top, hicon);
2328         EndPaint(hwnd, &ps);
2329         SetWindowText(hwnd, buf);
2330
2331         return 0;
2332
2333 } /* kwin_paint */
2334
2335
2336 /*+
2337  * Function: Window proceedure for the Kerberos control panel dialog.
2338  *
2339  * Parameters:
2340  *      hwnd - the window receiving the message.
2341  *
2342  *      message - the message to process.
2343  *
2344  *      wparam - wparam of the message.
2345  *
2346  *      lparam - lparam of the message.
2347  *
2348  * Returns: message dependent value.
2349  */
2350 LRESULT __export CALLBACK
2351 kwin_wnd_proc (
2352         HWND hwnd,
2353         UINT message,
2354         WPARAM wparam,
2355         LPARAM lparam)
2356 {
2357         LRESULT rc;
2358     int n;
2359
2360         if (message == wm_kerberos_changed) {       /* Message from the ccache */
2361                 n = ticket_init_list(GetDlgItem(hwnd, IDD_TICKET_LIST));
2362         EnableWindow(GetDlgItem(hwnd, IDD_TICKET_DELETE), n > 0);
2363
2364                 return 0;
2365         }
2366
2367         switch (message) {
2368         case WM_GETMINMAXINFO:
2369                 rc = kwin_getminmaxinfo(hwnd, wparam, lparam);
2370                 return rc;
2371
2372         case WM_DESTROY:
2373                 rc = kwin_destroy(hwnd, wparam, lparam);
2374                 return rc;
2375
2376         case WM_MEASUREITEM:
2377                 if (wparam == IDD_TICKET_LIST) {
2378                         rc = ticket_measureitem(hwnd, wparam, lparam);
2379                         return rc;
2380                 }
2381                 break;
2382
2383         case WM_DRAWITEM:
2384                 if (wparam == IDD_TICKET_LIST) {
2385                         rc = ticket_drawitem(hwnd, wparam, lparam);
2386                         return rc;
2387                 }
2388                 break;
2389
2390         case WM_SETCURSOR:
2391                 if (isblocking) {
2392                         SetCursor(LoadCursor(NULL, IDC_WAIT));
2393                         return TRUE;
2394                 }
2395                 break;
2396
2397         case WM_SIZE:
2398                 rc = kwin_size(hwnd, wparam, lparam);
2399                 return rc;
2400
2401         case WM_SYSCOMMAND:
2402                 rc = kwin_syscommand(hwnd, wparam, lparam);
2403                 return rc;
2404
2405         case WM_TIMER:
2406                 rc = kwin_timer(hwnd, wparam, lparam);
2407                 return 0;
2408
2409         case WM_PAINT:
2410                 rc = kwin_paint(hwnd, wparam, lparam);
2411                 return rc;
2412
2413         case WM_ERASEBKGND:
2414                 if (!IsIconic(hwnd))
2415                         break;
2416                 return 0;
2417
2418         case WM_KWIN_SETNAME:
2419                 kwin_init_name(hwnd, (char *) lparam);
2420         }
2421
2422         return DefDlgProc(hwnd, message, wparam, lparam);
2423
2424 } /* kwin_wnd_proc */
2425
2426
2427 /*+
2428  * Function: Dialog procedure called by the dialog manager
2429  *      to process dialog specific messages.
2430  *
2431  * Parameters:
2432  *      hwnd - the dialog receiving the message.
2433  *
2434  *      message - the message to process.
2435  *
2436  *      wparam - wparam of the message.
2437  *
2438  *      lparam - lparam of the message.
2439  *
2440  * Returns: TRUE if message handled locally, FALSE otherwise.
2441  */
2442 static BOOL CALLBACK
2443 kwin_dlg_proc (
2444         HWND hwnd,
2445         UINT message,
2446         WPARAM wparam,
2447         LPARAM lparam)
2448 {
2449         LRESULT rc;
2450
2451         switch (message) {
2452         case WM_INITDIALOG:
2453                 return kwin_initdialog(hwnd, wparam, lparam);
2454
2455         case WM_COMMAND:
2456                 rc = kwin_command(hwnd, wparam, lparam);
2457                 return TRUE;
2458         }
2459
2460         return FALSE;
2461
2462 } /* kwin_dlg_proc */
2463
2464
2465 /*+
2466  * Function: Initialize the kwin dialog class.
2467  *
2468  * Parameters:
2469  *      hinstance - the instance to initialize
2470  *
2471  * Returns: TRUE if dialog class registration is sucessfully, false otherwise.
2472  */
2473 static BOOL
2474 kwin_init (
2475         HINSTANCE hinstance)
2476 {
2477         WNDCLASS class;
2478         ATOM rc;
2479
2480         class.style = CS_HREDRAW | CS_VREDRAW;
2481         class.lpfnWndProc = (WNDPROC) kwin_wnd_proc;
2482         class.cbClsExtra = 0;
2483         class.cbWndExtra = DLGWINDOWEXTRA;
2484         class.hInstance = hinstance;
2485         class.hIcon = NULL;
2486 //              LoadIcon(hinstance, MAKEINTRESOURCE(IDI_KWIN));
2487         class.hCursor = NULL;
2488         class.hbrBackground = NULL;
2489         class.lpszMenuName = NULL;
2490         class.lpszClassName = KWIN_DIALOG_CLASS;
2491
2492         rc = RegisterClass (&class);
2493         assert(rc);
2494
2495         return rc;
2496
2497 } /* kwin_init */
2498
2499
2500 /*+
2501  * Function: Initialize the KWIN application.  This routine should
2502  *      only be called if no previous instance of the application
2503  *      exists.  Currently it only registers a class for the kwin
2504  *      dialog type.
2505  *
2506  * Parameters:
2507  *      hinstance - the instance to initialize
2508  *
2509  * Returns: TRUE if initialized sucessfully, false otherwise.
2510  */
2511 static BOOL
2512 init_application (
2513         HINSTANCE hinstance)
2514 {
2515         BOOL rc;
2516
2517         #ifdef KRB4
2518                 wm_kerberos_changed = krb_get_notification_message();
2519         #endif
2520
2521         #ifdef KRB5
2522                 wm_kerberos_changed = krb5_get_notification_message();
2523         #endif
2524
2525         rc = kwin_init(hinstance);
2526
2527         return rc;
2528
2529 } /* init_application */
2530
2531
2532 /*+
2533  * Function: Quits the KWIN application.  This routine should
2534  *      be called when the last application instance exits.
2535  *
2536  * Parameters:
2537  *      hinstance - the instance which is quitting.
2538  *
2539  * Returns: TRUE if initialized sucessfully, false otherwise.
2540  */
2541 static BOOL
2542 quit_application (
2543         HINSTANCE hinstance)
2544 {
2545         return TRUE;
2546 } /* quit_application */
2547
2548
2549 /*+
2550  * Function: Initialize the current instance of the KWIN application.
2551  *
2552  * Parameters:
2553  *      hinstance - the instance to initialize
2554  *
2555  *      ncmdshow - show flag to indicate wheather to come up minimized
2556  *              or not.
2557  *
2558  * Returns: TRUE if initialized sucessfully, false otherwise.
2559  */
2560 static BOOL
2561 init_instance (
2562         HINSTANCE hinstance,
2563         int ncmdshow)
2564 {
2565     WORD versionrequested;
2566     WSADATA wsadata;
2567     int rc;
2568         char buf[20];
2569         int i;
2570
2571         versionrequested = 0x0101;                      /* We need version 1.1 */
2572         rc = WSAStartup(versionrequested, &wsadata);
2573     if (rc != 0) {
2574                 MessageBox(NULL, "Couldn't initialize Winsock library", "", MB_OK | MB_ICONSTOP);
2575
2576                 return FALSE;
2577         }
2578
2579     if (versionrequested != wsadata.wVersion) {
2580                 WSACleanup();
2581                 MessageBox(NULL, "Winsock version 1.1 not available", "", MB_OK | MB_ICONSTOP);
2582
2583                 return FALSE;
2584     }
2585
2586         /*
2587          * Set up expiration action
2588          */
2589         GetPrivateProfileString(INI_EXPIRATION, INI_ALERT, "No",
2590                 buf, sizeof(buf), KERBEROS_INI);
2591         alert = _stricmp(buf, "Yes") == 0;
2592         GetPrivateProfileString(INI_EXPIRATION, INI_BEEP, "No",
2593                 buf, sizeof(buf), KERBEROS_INI);
2594         beep = _stricmp(buf, "Yes") == 0;
2595
2596         /*
2597          * Load clock icons
2598          */
2599         for (i = IDI_FIRST_CLOCK; i <= IDI_LAST_CLOCK; i++)
2600                 kwin_icons[i - IDI_FIRST_CLOCK] = LoadIcon(hinstance, MAKEINTRESOURCE(i));
2601
2602         #ifdef KRB4
2603             krb_start_session(NULL);
2604         #endif
2605
2606         #ifdef KRB5
2607         {
2608             krb5_error_code code;
2609
2610                 code = krb5_init_context(&k5_context);
2611             if (! code) {
2612                         krb5_init_ets(k5_context);
2613                         code = k5_init_ccache (&k5_ccache);
2614             }
2615             if (code) {
2616                 com_err (NULL, code, "while initializing program");
2617                 return FALSE;
2618             }
2619             k5_name_from_ccache (k5_ccache);
2620         }
2621         #endif
2622
2623         return TRUE;
2624
2625 } /* init_instance */
2626
2627
2628 /*+
2629  * Function: Quits the current instance of the KWIN application.
2630  *
2631  * Parameters:
2632  *      hinstance - the instance to quit.
2633  *
2634  * Returns: TRUE if termination was sucessfully, false otherwise.
2635  */
2636 static BOOL
2637 quit_instance (
2638         HINSTANCE hinstance)
2639 {
2640         int i;
2641
2642         #ifdef KRB4
2643             krb_end_session((char *) NULL);
2644         #endif
2645
2646     #ifdef KRB5     /* FIXME */
2647         krb5_cc_close (k5_context, k5_ccache);
2648     #endif
2649
2650         WSACleanup();
2651
2652         /*
2653          * Unload clock icons
2654          */
2655         for (i = IDI_FIRST_CLOCK; i <= IDI_LAST_CLOCK; i++)
2656                 DestroyIcon(kwin_icons[i - IDI_FIRST_CLOCK]);
2657
2658         return TRUE;
2659
2660 } /* quit_instance */
2661
2662
2663 /*+
2664  * Function: Main routine called on program invocation.
2665  *
2666  * Parameters:
2667  *      hinstance - the current instance
2668  *
2669  *      hprevinstance - previous instance if one exists or NULL.
2670  *
2671  *      cmdline - the command line string passed by Windows.
2672  *
2673  *      ncmdshow - show flag to indicate wheather to come up minimized
2674  *              or not.
2675  *
2676  * Returns: TRUE if initialized sucessfully, false otherwise.
2677  */
2678 int PASCAL
2679 WinMain (
2680         HINSTANCE hinst,
2681         HINSTANCE hprevinstance,
2682         LPSTR cmdline,
2683         int ncmdshow)
2684 {
2685         DLGPROC dlgproc;
2686         HWND hwnd;
2687         HACCEL haccel;
2688         MSG msg;
2689         char *p;
2690         char buf[MAX_K_NAME_SZ + 9];
2691         char name[MAX_K_NAME_SZ];
2692
2693         strcpy(buf, cmdline);
2694         action = LOGIN_AND_RUN;
2695         name[0] = 0;
2696         p = strtok(buf, " ,");
2697
2698         while (p != NULL) {
2699                 if (_stricmp(p, "/exit") == 0)
2700                         action = LOGIN_AND_EXIT;
2701                 else if (_stricmp(p, "/minimize") == 0)
2702                         action = LOGIN_AND_MINIMIZE;
2703                 else
2704                         strcpy(name, p);
2705
2706                 p = strtok(NULL, " ,");
2707         }
2708
2709         dlgncmdshow = ncmdshow;
2710         hinstance = hinst;
2711
2712         /*
2713          * If a previous instance of this application exits, bring it
2714          * to the front and exit.
2715          */
2716         if (hprevinstance != NULL) {
2717                 hwnd = FindWindow(KWIN_DIALOG_CLASS, NULL);
2718
2719                 if (IsWindow(hwnd) && IsWindowVisible(hwnd)) {
2720                         if (GetWindowWord(hwnd, GWW_HINSTANCE) == hprevinstance) {
2721                                 if (name[0])
2722                                         SendMessage(hwnd, WM_KWIN_SETNAME, 0, (LONG) name);
2723
2724                 ShowWindow(hwnd, ncmdshow);
2725                                 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
2726                                         SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2727
2728                                 return FALSE;
2729                         }
2730                 }
2731         }
2732
2733         if (hprevinstance == NULL)
2734                 if (!init_application(hinstance))
2735                         return FALSE;
2736
2737         if (!init_instance(hinstance, ncmdshow))
2738                 return FALSE;
2739
2740         dlgproc = (FARPROC) MakeProcInstance(kwin_dlg_proc, hinstance);
2741         assert(dlgproc != NULL);
2742
2743         if (dlgproc == NULL)
2744                 return 1;
2745
2746         hwnd = CreateDialogParam(hinstance, MAKEINTRESOURCE (ID_KWIN),
2747                                 HWND_DESKTOP, dlgproc, (LONG) name);
2748         assert(hwnd != NULL);
2749
2750         if (hwnd == NULL)
2751                 return 1;
2752         haccel = LoadAccelerators(hinstance, MAKEINTRESOURCE(IDA_KWIN));
2753         assert(hwnd != NULL);
2754
2755     while (GetMessage(&msg, NULL, 0, 0)) {
2756                 if (!TranslateAccelerator(hwnd, haccel, &msg) &&
2757                         !IsDialogMessage(hwnd, &msg)) {
2758                 TranslateMessage(&msg);
2759                         DispatchMessage(&msg);
2760                 }
2761         }
2762
2763         DestroyWindow(hwnd);
2764         FreeProcInstance((FARPROC) dlgproc);
2765
2766         return 0;
2767
2768 } /* WinMain */
2769
2770
2771 #if 0
2772
2773         #define WM_ASYNC_COMPLETED (WM_USER + 1)
2774         #define GETHOSTBYNAME_CLASS "krb_gethostbyname"
2775         static HTASK htaskasync;                        /* Asynchronos call in progress */
2776         static BOOL iscompleted;                        /* True when async call is completed */
2777
2778         /*
2779         * This routine is called to cancel a blocking hook call within
2780         * the Kerberos library.  The need for this routine arises due
2781         * to bugs which exist in existing WINSOCK implementations.  We
2782         * blocking gethostbyname with WSAASyncGetHostByName.  In order
2783         * to cancel such an operation, this routine must be called.
2784         * Applications may call this routine in addition to calls to
2785         * WSACancelBlockingCall to get any sucy Async calls canceled.
2786         * Return values are as they would be for WSACancelAsyncRequest.
2787         */
2788         int
2789         krb_cancel_blocking_call(void)
2790         {
2791                 if (htaskasync == NULL)
2792                         return 0;
2793                 iscompleted = TRUE;
2794
2795                 return WSACancelAsyncRequest(htask);
2796
2797         } /* krb_cancel_blocking_call */
2798
2799
2800         /*
2801         * Window proceedure for temporary Windows created in
2802         * krb_gethostbyname.  Fields completion messages.
2803         */
2804         LRESULT __export CALLBACK krb_gethostbyname_wnd_proc(
2805                 HWND hwnd,
2806                 UINT message,
2807                 WPARAM wparam,
2808                 LPARAM lparam)
2809         {
2810                 if (message == WM_ASYNC_COMPLETED) {
2811                         iscompleted = TRUE;
2812                         return 0;
2813                 }
2814
2815                 return DefWindowProc(hwnd, message, wparam, lparam);
2816
2817         } /* krb_gethostbyname_wnd_proc */
2818
2819
2820         /*
2821         * The WINSOCK routine gethostbyname has a bug in both FTP and NetManage
2822         * implementations which causes the blocking hook, if any, not to be
2823         * called.  This routine attempts to work around the problem by using
2824         * the async routines to emulate the functionality of the synchronous
2825         * routines
2826         */
2827         struct hostent FAR *PASCAL FAR
2828         krb_gethostbyname(
2829                 const char FAR *name)
2830         {
2831                 HWND hwnd;
2832                 char buf[MAXGETHOSTSTRUCT];
2833                 BOOL FARPROC blockinghook;
2834                 WNDCLASS wc;
2835                 static BOOL isregistered;
2836
2837                 blockinghook = WSASetBlockingHook(NULL);
2838                 WSASetBlockingHook(blockinghook);
2839
2840                 if (blockinghook == NULL)
2841                         return gethostbyname(name);
2842
2843                 if (RegisterWndClass() == NULL)
2844                         return gethostbyname(name);
2845
2846                 if (!isregistered) {
2847                         wc.style = 0;
2848                         wc.lpfnWndProc = gethostbyname_wnd_proc;
2849                         wc.cbClsExtra = 0;
2850                         wc.cbWndExtra = 0;
2851                         wc.hInstance = hlibinstance;
2852                         wc.hIcon = NULL;
2853                         wc.hCursor = NULL;
2854                         wc.hbrBackground = NULL;
2855                         wc.lpszMenuName  = NULL;
2856                         wc.lpszClassName = GETHOSTBYNAME_CLASS;
2857
2858                         if (!RegisterClass(&wc))
2859                                 return gethostbyname(name);
2860
2861                         isregistered = TRUE;
2862                 }
2863
2864                 hwnd = CreateWindow(GETHOSTBYNAME_CLASS, "", WS_OVERLAPPED,
2865                         -100, -100, 0, 0, HWND_DESKTOP, NULL, hlibinstance, NULL);
2866                 if (hwnd == NULL)
2867                         return gethostbyname(name);
2868
2869                 htaskasync =
2870                         WSAAsyncGetHostByName(hwnd, WM_ASYNC_COMPLETED, name, buf, sizeof(buf));
2871                 b = blockinghook(NULL);
2872
2873         } /* krb_gethostbyname */
2874
2875 #endif
2876
2877 #ifdef KRB5
2878
2879 /*+
2880  * Function: destroys all tickets in a k5 ccache
2881  *
2882  * Parameters:
2883  *  none
2884  *
2885  * Returns: K5 error code (0 == success)
2886  */
2887 static krb5_error_code
2888 k5_dest_tkt (void) {
2889     krb5_error_code code;
2890     krb5_principal princ;
2891
2892     if (code = krb5_cc_get_principal(k5_context, k5_ccache, &princ)) {
2893         com_err (NULL, code, "while retrieving principal name");
2894         return code;
2895     }
2896
2897     code = krb5_cc_initialize (k5_context, k5_ccache, princ);
2898     if (code != 0) {
2899         com_err (NULL, code, "when re-initializing cache");
2900         krb5_free_principal (k5_context, princ);
2901         return code;
2902     }
2903
2904     krb5_free_principal (k5_context, princ);
2905     return code;
2906 }
2907
2908 /*+
2909  * 
2910  * k5_get_num_cred
2911  * 
2912  * Returns: number of creds in the credential cache, -1 on error
2913  * 
2914  */
2915 static int
2916 k5_get_num_cred (int verbose) {
2917     krb5_error_code code;
2918     krb5_cc_cursor cursor;
2919     krb5_creds c;
2920     int ncreds = 0;
2921
2922     /* Turn off OPENCLOSE and leave open while we use ccache */
2923     if (code = krb5_cc_set_flags(k5_context, k5_ccache, 0)) {
2924         if (code == KRB5_FCC_NOFILE)
2925             return 0;
2926         if (verbose)
2927             com_err (NULL, code,
2928                 "while setting cache flags (ticket cache %s)",
2929                 krb5_cc_get_name(k5_context, k5_ccache));
2930         return -1;
2931     }
2932
2933     if (code = krb5_cc_start_seq_get(k5_context, k5_ccache, &cursor)) {
2934         if (verbose)
2935             com_err (NULL, code, "while starting to retrieve tickets.");
2936         return -1;
2937     }
2938
2939     while (1) {                                 /* Loop and get creds */
2940         code = krb5_cc_next_cred(k5_context, k5_ccache, &cursor, &c);
2941         if (code)
2942             break;
2943         ++ncreds;
2944     }
2945
2946     if (code != KRB5_CC_END) {                  /* Error while looping??? */
2947         if (verbose)
2948             com_err (NULL, code, "while retrieving a ticket.");
2949         return -1;
2950     }
2951
2952     if (code = krb5_cc_end_seq_get(k5_context, k5_ccache, &cursor)) {
2953         if (verbose)
2954             com_err (NULL, code, "while closing ccache.");
2955     } else if (code = krb5_cc_set_flags(k5_context, k5_ccache, KRB5_TC_OPENCLOSE)) {
2956         if (verbose)
2957             com_err(NULL, code, "while closing ccache.");
2958     }
2959
2960     return ncreds;
2961 }
2962
2963 static int
2964 k5_get_num_cred2 () {
2965     krb5_error_code code;
2966     krb5_cc_cursor cursor;
2967     krb5_creds c;
2968     int ncreds = 0;
2969
2970     code = krb5_cc_start_seq_get (k5_context, k5_ccache, &cursor);
2971     if (code == KRB5_FCC_NOFILE)
2972         return 0;
2973
2974     while (1) {
2975         code = krb5_cc_next_cred(k5_context, k5_ccache, &cursor, &c);
2976         if (code)
2977             break;
2978         ++ncreds;
2979     }
2980     if (code == KRB5_CC_END)
2981         krb5_cc_end_seq_get(k5_context, k5_ccache, &cursor);
2982
2983     return ncreds;
2984 }
2985
2986 /*+
2987  * Function: Parses fullname into name, instance and realm
2988  *
2989  * Parameters:
2990  *  name - buffer filled with name of user
2991  *
2992  *  realm - buffer filled with realm of user
2993  *
2994  *  fullname - string in form name.instance@realm
2995  *
2996  * Returns: 0
2997  */
2998 static int
2999 k5_kname_parse (char *name, char *realm, char *fullname) {
3000     char *ptr;                                  /* For parsing */
3001
3002     ptr = strchr (fullname, '@');               /* Name, realm separator */
3003
3004     if (ptr != NULL)                            /* Get realm */
3005         strcpy (realm, ptr + 1);
3006     else
3007         *realm = '\0';
3008
3009     if (ptr != NULL) {                          /* Get the name */
3010         strncpy (name, fullname, ptr - fullname);
3011         name[ptr - fullname] = '\0';
3012     } else
3013         strcpy (name, fullname);
3014
3015     ptr = strchr (name, '.');                   /* K4 compatability */
3016     if (ptr != NULL)
3017         *ptr = '\0';
3018
3019     return 0;
3020 }
3021 /*+
3022  * Function: Initializes ccache and catches illegal caches such as
3023  *  bad format or no permissions.
3024  *
3025  * Parameters:
3026  *  ccache - credential cache structure to use
3027  *
3028  * Returns: krb5_error_code
3029  */
3030 static krb5_error_code
3031 k5_init_ccache (krb5_ccache *ccache) {
3032     krb5_error_code code;
3033     krb5_principal princ;
3034     FILE *fp;
3035
3036     code = krb5_cc_default (k5_context, ccache); // Initialize the ccache
3037     if (code)
3038         return code;
3039
3040     code = krb5_cc_get_principal (k5_context, *ccache, &princ);
3041     if (code == KRB5_FCC_NOFILE) {              // Doesn't exist yet
3042         fp = fopen (krb5_cc_get_name(k5_context, *ccache), "w");
3043         if (fp == NULL)                         // Can't open it
3044             return KRB5_FCC_PERM;
3045         fclose (fp);
3046     }
3047
3048     if (code) {                                 // Bad, delete and try again
3049         remove (krb5_cc_get_name(k5_context, *ccache));
3050         code = krb5_cc_get_principal (k5_context, *ccache, &princ);
3051         if (code == KRB5_FCC_NOFILE)            // Doesn't exist yet
3052             return 0;
3053         if (code)
3054             return code;
3055     }
3056
3057     krb5_free_principal (k5_context, princ);
3058     return 0;
3059 }
3060 /*+
3061  * 
3062  * Function: Reads the name and realm out of the ccache.
3063  * 
3064  * Parameters:
3065  *  ccache - credentials cache to get info from
3066  * 
3067  *  name - buffer to hold user name
3068  * 
3069  *  realm - buffer to hold the realm
3070  * 
3071  * 
3072  * Returns: TRUE if read names, FALSE if not
3073  * 
3074  */
3075 static int
3076 k5_name_from_ccache (krb5_ccache k5_ccache) {
3077     krb5_error_code code;
3078     krb5_principal princ;
3079         char name[ANAME_SZ];
3080         char realm[REALM_SZ];
3081     char *defname;
3082
3083     if (code = krb5_cc_get_principal(k5_context, k5_ccache, &princ))
3084         return FALSE;
3085
3086     code = krb5_unparse_name(k5_context, princ, &defname);
3087     if (code) {
3088         krb5_free_principal (k5_context, princ);
3089         return FALSE;
3090     }
3091
3092     k5_kname_parse(name, realm, defname);       // Extract the components
3093     WritePrivateProfileString(INI_DEFAULTS, INI_USER, name, KERBEROS_INI);
3094         WritePrivateProfileString(INI_DEFAULTS, INI_REALM, realm, KERBEROS_INI);
3095
3096     krb5_free_principal(k5_context, princ);
3097     free (defname);
3098
3099     return TRUE;
3100 }
3101 #endif /* KRB5 */