windows-netidmgr-20070505
[openafs.git] / src / WINNT / netidmgr_plugin / afsnewcreds.c
1 /*
2  * Copyright (c) 2005,2006 Secure Endpoints Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without
7  * restriction, including without limitation the rights to use, copy,
8  * modify, merge, publish, distribute, sublicense, and/or sell copies
9  * of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24
25 /* $Id$ */
26
27 #include<afscred.h>
28 #include<commctrl.h>
29 #include<assert.h>
30 #include<netidmgr_version.h>
31 #include<htmlhelp.h>
32 #include<help/afsplhlp.h>
33
34 /* UI stuff */
35
36 #define WMNC_AFS_UPDATE_ROWS (WMNC_USER + 1)
37
38 typedef struct tag_afs_ident_token_set {
39     khm_handle ident;
40     afs_cred_list * l;
41     khm_boolean add_new;
42     khm_boolean update_info;
43 } afs_ident_token_set;
44
45
46 void 
47 afs_cred_flush_rows(afs_cred_list * l) {
48     int i;
49
50     for(i=0; i<l->n_rows; i++) {
51         if(l->rows[i].cell)
52             PFREE(l->rows[i].cell);
53         if(l->rows[i].realm)
54             PFREE(l->rows[i].realm);
55     }
56
57     if(l->nc_rows) {
58         ZeroMemory(l->rows, sizeof(l->rows[0]) * l->nc_rows);
59     }
60
61     l->n_rows = 0;
62 }
63
64 void 
65 afs_cred_free_rows(afs_cred_list * l) {
66
67     afs_cred_flush_rows(l);
68
69     if(l->rows)
70         PFREE(l->rows);
71     l->rows = NULL;
72     l->n_rows = 0;
73     l->nc_rows = 0;
74 }
75
76 void 
77 afs_cred_assert_rows(afs_cred_list * l, int n) {
78     afs_cred_row * rows;
79
80     if(n > l->nc_rows) {
81         l->nc_rows = UBOUNDSS(n, AFS_DLG_ROW_ALLOC, AFS_DLG_ROW_ALLOC);
82         rows = PMALLOC(sizeof(afs_cred_row) * l->nc_rows);
83         ZeroMemory(rows, sizeof(afs_cred_row) * l->nc_rows);
84
85         if(l->rows) {
86             if(l->n_rows)
87                 memcpy(rows, l->rows, sizeof(afs_cred_row) * l->n_rows);
88             PFREE(l->rows);
89         }
90         l->rows = rows;
91     }
92 }
93
94 void 
95 afs_cred_delete_row(afs_cred_list * l, int i) {
96     if (i < 0 || i >= l->n_rows)
97         return;
98
99     if(i < (l->n_rows - 1)) {
100         if(l->rows[i].cell)
101             PFREE(l->rows[i].cell);
102         if(l->rows[i].realm)
103             PFREE(l->rows[i].realm);
104         memmove(&(l->rows[i]),
105                 &(l->rows[i+1]),
106                 ((l->n_rows - (i+1)) * 
107                  sizeof(l->rows[0])));
108     }
109     l->n_rows--;
110 }
111
112 afs_cred_row * 
113 afs_cred_get_new_row(afs_cred_list * l) {
114     afs_cred_row * r;
115
116     afs_cred_assert_rows(l, l->n_rows + 1);
117     r = &(l->rows[l->n_rows]);
118     l->n_rows++;
119
120     ZeroMemory(r, sizeof(*r));
121
122     return r;
123 }
124
125 afs_cred_row *
126 afs_cred_add_row_from_cred(afs_cred_list * l,
127                            khm_handle cred) {
128     khm_int32 rv;
129     afs_cred_row * row;
130     khm_size cb;
131     wchar_t cell[MAXCELLCHARS];
132     int i;
133
134     cb = sizeof(cell);
135     rv = kcdb_cred_get_attr(cred,
136                             afs_attr_cell,
137                             NULL,
138                             cell,
139                             &cb);
140 #ifdef DEBUG
141     assert(rv == KHM_ERROR_SUCCESS && cb != 0);
142 #endif
143
144     /* check if we already have the cell listed. */
145     for (i=0; i<l->n_rows; i++) {
146         if (!_wcsicmp(l->rows[i].cell, cell))
147             return &l->rows[i];
148     }
149
150     row = afs_cred_get_new_row(l);
151
152     row->cell = PMALLOC(cb);
153     StringCbCopy(row->cell, cb, cell);
154
155     cb = sizeof(row->method);
156     rv = kcdb_cred_get_attr(cred,
157                             afs_attr_method,
158                             NULL,
159                             &row->method,
160                             &cb);
161
162     if (KHM_FAILED(rv)) {
163         row->method = AFS_TOKEN_AUTO;
164         row->realm = NULL;
165         return row;
166     }
167
168     rv = kcdb_cred_get_attr(cred,
169                             afs_attr_realm,
170                             NULL,
171                             NULL,
172                             &cb);
173
174     if (rv == KHM_ERROR_TOO_LONG && cb > sizeof(wchar_t)) {
175         row->realm = PMALLOC(cb);
176 #ifdef DEBUG
177         assert(row->realm);
178 #endif
179         rv = kcdb_cred_get_attr(cred,
180                                 afs_attr_realm,
181                                 NULL,
182                                 row->realm,
183                                 &cb);
184
185         if (KHM_FAILED(rv)) {
186             if (row->realm)
187                 PFREE(row->realm);
188             row->realm = NULL;
189         }
190     } else {
191         row->realm = NULL;
192     }
193
194     return row;
195 }
196
197 khm_int32 KHMAPI
198 afs_cred_add_cred_proc(khm_handle cred, void * rock) {
199     afs_cred_list * l = (afs_cred_list *) rock;
200     khm_int32 t;
201
202     if (KHM_FAILED(kcdb_cred_get_type(cred, &t)) ||
203         t != afs_credtype_id)
204         return KHM_ERROR_SUCCESS;
205
206     afs_cred_add_row_from_cred(l, cred);
207
208     return KHM_ERROR_SUCCESS;
209 }
210
211 void
212 afs_cred_get_context_creds(afs_cred_list *l,
213                            khui_action_context * ctx) {
214     khm_handle credset = NULL;
215
216     if (KHM_FAILED(kcdb_credset_create(&credset)))
217         return;
218
219     if (KHM_FAILED(kcdb_credset_extract_filtered(credset,
220                                                  NULL,
221                                                  khui_context_cursor_filter,
222                                                  (void *) ctx)))
223         goto _cleanup;
224
225     kcdb_credset_apply(credset,
226                        afs_cred_add_cred_proc,
227                        (void *) l);
228
229  _cleanup:
230     if (credset)
231         kcdb_credset_delete(credset);
232 }
233
234 khm_int32 KHMAPI
235 afs_get_id_creds_apply_proc(khm_handle cred, void * rock) {
236     khm_int32 t;
237     afs_ident_token_set * ts;
238     afs_cred_list * l;
239     khm_handle ident;
240     wchar_t cell[MAXCELLCHARS];
241     khm_size cb;
242     int i;
243     khm_int32 cflags = 0;
244
245     ts = (afs_ident_token_set *) rock;
246     l = ts->l;
247
248     kcdb_cred_get_type(cred, &t);
249     if (t != afs_credtype_id)
250         return KHM_ERROR_SUCCESS;
251
252     cb = sizeof(cell);
253     if (KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_cell,
254                                       NULL,
255                                       cell, &cb)))
256         return KHM_ERROR_SUCCESS;
257
258     kcdb_cred_get_flags(cred, &cflags);
259
260     kcdb_cred_get_identity(cred, &ident);
261
262     if (kcdb_identity_is_equal(ident, ts->ident)) {
263
264         for (i=0; i < l->n_rows; i++) {
265             if (!_wcsicmp(l->rows[i].cell, cell)) {
266                 khm_int32 method;
267
268                 /* if the token exists, then these are implied */
269                 l->rows[i].flags =
270                     DLGROW_FLAG_EXISTS |
271                     DLGROW_FLAG_CHECKED |
272                     DLGROW_FLAG_VALID;
273
274                 if (cflags & KCDB_CRED_FLAG_EXPIRED)
275                     l->rows[i].flags |= DLGROW_FLAG_EXPIRED;
276
277                 if (ts->update_info) {
278                     wchar_t realm[KHUI_MAXCCH_NAME];
279
280                     cb = sizeof(method);
281                     if (KHM_SUCCEEDED
282                         (kcdb_cred_get_attr(cred, afs_attr_method,
283                                             NULL,
284                                             &method, &cb)) &&
285                         afs_is_valid_method_id(method))
286                         l->rows[i].method = method;
287
288                     cb = sizeof(realm);
289                     if (KHM_SUCCEEDED
290                         (kcdb_cred_get_attr(cred, afs_attr_realm,
291                                             NULL,
292                                             realm, &cb)) &&
293                         cb > sizeof(wchar_t)) {
294
295                         if (l->rows[i].realm)
296                             PFREE(l->rows[i].realm);
297                         l->rows[i].realm = PMALLOC(cb);
298                         StringCbCopy(l->rows[i].realm,
299                                      cb,
300                                      realm);
301                     }
302                 }
303                 break;
304             }
305         }
306
307         /* not found? add! */
308         if (i >= l->n_rows && ts->add_new) {
309             afs_cred_row * r;
310
311             r = afs_cred_add_row_from_cred(l, cred);
312
313             r->flags = DLGROW_FLAG_VALID | DLGROW_FLAG_CHECKED |
314                 DLGROW_FLAG_EXISTS;
315
316             if (cflags & KCDB_CRED_FLAG_EXPIRED)
317                 r->flags |= DLGROW_FLAG_EXPIRED;
318         }
319
320     } else {                    /* different identities */
321
322         for (i=0; i < l->n_rows; i++) {
323             if (!_wcsicmp(l->rows[i].cell, cell)) {
324                 l->rows[i].flags =
325                     DLGROW_FLAG_NOTOWNED | DLGROW_FLAG_EXISTS |
326                     DLGROW_FLAG_VALID | DLGROW_FLAG_CHECKED;
327                 if (cflags & KCDB_CRED_FLAG_EXPIRED)
328                     l->rows[i].flags |= DLGROW_FLAG_EXPIRED;
329             }
330         }
331
332     }
333
334     kcdb_identity_release(ident);
335
336     return KHM_ERROR_SUCCESS;
337 }
338
339 void
340 afs_remove_token_from_identities(wchar_t * cell) {
341     wchar_t * idents = NULL;
342     wchar_t * t;
343     khm_size cb_id;
344     khm_size n_id = 0;
345
346     do {
347         if (kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG,
348                                KCDB_IDENT_FLAG_CONFIG,
349                                NULL,
350                                &cb_id,
351                                &n_id) != KHM_ERROR_TOO_LONG ||
352             n_id == 0) {
353             if (idents)
354                 PFREE(idents);
355             return;
356         }
357
358         if (idents)
359             PFREE(idents);
360         idents = PMALLOC(cb_id);
361
362         if (kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG,
363                                KCDB_IDENT_FLAG_CONFIG,
364                                idents,
365                                &cb_id,
366                                &n_id) == KHM_ERROR_SUCCESS)
367             break;
368     } while(TRUE);
369
370     for (t=idents;
371          t && *t;
372          t = multi_string_next(t)) {
373
374         khm_handle h_id = NULL;
375         khm_handle csp_ident = NULL;
376         khm_handle csp_afs = NULL;
377         khm_size cb;
378         wchar_t vbuf[1024];
379         wchar_t * tbuf = NULL;
380
381         kcdb_identity_create(t, 0, &h_id);
382         if (h_id == NULL) {
383 #ifdef DEBUG
384             assert(FALSE);
385 #endif
386             continue;
387         }
388
389         if (KHM_FAILED(kcdb_identity_get_config(h_id, 0, &csp_ident)))
390             goto _cleanup_loop;
391
392         if (KHM_FAILED(khc_open_space(csp_ident, CSNAME_AFSCRED,
393                                       0, &csp_afs)))
394             goto _cleanup_loop;
395
396         if (khc_read_multi_string(csp_afs, L"Cells", NULL, &cb)
397             != KHM_ERROR_TOO_LONG)
398             goto _cleanup_loop;
399
400         if (cb < sizeof(vbuf))
401             tbuf = vbuf;
402         else
403             tbuf = PMALLOC(cb);
404
405         if (khc_read_multi_string(csp_afs, L"Cells", tbuf, &cb)
406             != KHM_ERROR_SUCCESS)
407             goto _cleanup_loop;
408
409         if (multi_string_find(tbuf, cell, 0) == NULL)
410             goto _cleanup_loop;
411
412         multi_string_delete(tbuf, cell, 0);
413
414         khc_write_multi_string(csp_afs, L"Cells", tbuf);
415
416     _cleanup_loop:
417         kcdb_identity_release(h_id);
418         if (csp_ident)
419             khc_close_space(csp_ident);
420         if (csp_afs)
421             khc_close_space(csp_afs);
422         if (tbuf && tbuf != vbuf)
423             PFREE(tbuf);
424     }
425
426     if (idents)
427         PFREE(idents);
428 }
429
430 khm_boolean
431 afs_check_add_token_to_identity(wchar_t * cell, khm_handle ident,
432                                 khm_handle * ident_conflict) {
433     wchar_t * idents = NULL;
434     wchar_t * t;
435     khm_size cb_id;
436     khm_size n_id = 0;
437     khm_boolean ok_to_add = TRUE;
438
439     /* check if this cell is listed for any other identity. */
440
441     do {
442         if (kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG,
443                                KCDB_IDENT_FLAG_CONFIG,
444                                NULL,
445                                &cb_id,
446                                &n_id) != KHM_ERROR_TOO_LONG ||
447             n_id == 0) {
448             if (idents)
449                 PFREE(idents);
450             return TRUE;
451         }
452
453         if (idents)
454             PFREE(idents);
455         idents = PMALLOC(cb_id);
456
457         if (kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG,
458                                KCDB_IDENT_FLAG_CONFIG,
459                                idents,
460                                &cb_id,
461                                &n_id) == KHM_ERROR_SUCCESS)
462             break;
463     } while(TRUE);
464
465     for (t=idents;
466          ok_to_add && t && *t;
467          t = multi_string_next(t)) {
468
469         khm_handle h_id = NULL;
470         khm_handle csp_ident = NULL;
471         khm_handle csp_afs = NULL;
472         khm_size cb;
473         wchar_t vbuf[1024];
474         wchar_t * tbuf = NULL;
475
476         kcdb_identity_create(t, 0, &h_id);
477         if (h_id == NULL) {
478 #ifdef DEBUG
479             assert(FALSE);
480 #endif
481             continue;
482         }
483
484         if (kcdb_identity_is_equal(h_id, ident)) {
485             kcdb_identity_release(h_id);
486             continue;
487         }
488
489         if (KHM_FAILED(kcdb_identity_get_config(h_id, 0, &csp_ident)))
490             goto _cleanup_loop;
491
492         if (KHM_FAILED(khc_open_space(csp_ident, CSNAME_AFSCRED,
493                                       0, &csp_afs)))
494             goto _cleanup_loop;
495
496         if (khc_read_multi_string(csp_afs, L"Cells", NULL, &cb)
497             != KHM_ERROR_TOO_LONG)
498             goto _cleanup_loop;
499
500         if (cb < sizeof(vbuf))
501             tbuf = vbuf;
502         else
503             tbuf = PMALLOC(cb);
504
505         if (khc_read_multi_string(csp_afs, L"Cells", tbuf, &cb)
506             != KHM_ERROR_SUCCESS)
507             goto _cleanup_loop;
508
509         if (multi_string_find(tbuf, cell, 0) == NULL)
510             goto _cleanup_loop;
511
512         /* we found another identity which gets tokens for the
513            same cell */
514
515         ok_to_add = FALSE;
516
517         if (ident_conflict) {
518             *ident_conflict = h_id;
519             kcdb_identity_hold(h_id);
520         }
521
522     _cleanup_loop:
523         kcdb_identity_release(h_id);
524         if (csp_ident)
525             khc_close_space(csp_ident);
526         if (csp_afs)
527             khc_close_space(csp_afs);
528         if (tbuf && tbuf != vbuf)
529             PFREE(tbuf);
530     }
531
532     if (idents)
533         PFREE(idents);
534
535     return ok_to_add;
536 }
537
538
539 void 
540 afs_cred_get_identity_creds(afs_cred_list * l, 
541                             khm_handle ident,
542                             khm_boolean * penabled) {
543     khm_handle h_id = NULL;
544     khm_handle h_afs = NULL;
545     khm_handle h_cells = NULL;  /* per identity cells space */
546     khm_handle h_gcells = NULL; /* global cells space */
547     khm_boolean load_defs = TRUE;
548     khm_size cbi;
549     wchar_t * ms = NULL;
550     wchar_t * s = NULL;
551     afs_ident_token_set ts;
552     khm_int32 t;
553
554     if (penabled)
555         *penabled = TRUE;
556
557     afs_cred_flush_rows(l);
558
559     kcdb_identity_get_config(ident, 0, &h_id);
560     if(!h_id) 
561         goto _done_config;
562
563     if(KHM_FAILED(khc_open_space(h_id, CSNAME_AFSCRED, 
564                                  0, &h_afs)))
565         goto _done_config;
566
567     if (penabled) {
568         t = 1;
569         if (KHM_FAILED(khc_read_int32(h_afs, L"AFSEnabled", &t)))
570             khc_read_int32(csp_params, L"AFSEnabled", &t);
571         *penabled = !!t;
572     }
573
574     if(KHM_FAILED(khc_open_space(h_afs, L"Cells", 
575                                  0, &h_cells)))
576         goto _done_config;
577
578     if(khc_read_multi_string(h_afs, L"Cells", NULL, &cbi) != 
579        KHM_ERROR_TOO_LONG)
580         goto _done_config;
581
582     load_defs = FALSE;
583
584     ms = PMALLOC(cbi);
585     ZeroMemory(ms, cbi);
586
587     khc_read_multi_string(h_afs, L"Cells", ms, &cbi);
588
589     s = ms;
590     for(s = ms; s && *s; s = multi_string_next(s)) {
591         afs_cred_row * r;
592         size_t cb;
593         khm_handle h_cell = NULL;
594
595         /* is this a valid cell name? */
596         if(FAILED(StringCbLength(s, MAXCELLCHARS, &cb)))
597             continue;
598         cb += sizeof(wchar_t);
599
600         r = afs_cred_get_new_row(l);
601
602         r->cell = PMALLOC(cb);
603         StringCbCopy(r->cell, cb, s);
604
605         r->realm = NULL;
606         r->method = 0;
607         r->flags = 0;
608
609         if(KHM_SUCCEEDED(khc_open_space(h_cells, s, 
610                                         0, &h_cell))) {
611             khm_int32 i;
612             wchar_t wname[KHUI_MAXCCH_NAME];
613             khm_size cb;
614
615             if(khc_read_string(h_cell, L"Realm", 
616                                NULL, &cbi) == 
617                KHM_ERROR_TOO_LONG &&
618                cbi > sizeof(wchar_t)) {
619
620                 r->realm = PMALLOC(cbi);
621                 khc_read_string(h_cell, L"Realm", r->realm, &cbi);
622             }
623
624             i = AFS_TOKEN_AUTO;
625
626             cb = sizeof(wname);
627             if (KHM_SUCCEEDED(khc_read_string(h_cell, L"MethodName",
628                                               wname, &cb))) {
629
630                 r->method = afs_get_method_id(wname);
631
632                 /* remove the deprecated value if it is present. */
633                 khc_remove_value(h_cell, L"Method", 0);
634
635             } else if (KHM_SUCCEEDED(khc_read_int32(h_cell, 
636                                                     L"Method", &i))) {
637                 /* the Method property is deprecated.  We detect and
638                    correct this whenever possible. */
639
640                 if (!afs_is_valid_method_id(i))
641                     i = AFS_TOKEN_AUTO;
642
643                 r->method = i;
644
645                 afs_get_method_name(i, wname, sizeof(wname));
646
647                 khc_write_string(h_cell, L"MethodName",
648                                  wname);
649
650                 khc_remove_value(h_cell, L"Method", 0);
651             }
652
653             khc_close_space(h_cell);
654         }
655     }
656
657     if(ms) {
658         PFREE(ms);
659         ms = NULL;
660     }
661
662  _done_config:
663
664     if (load_defs) {
665         /* We want to load defaults */
666         char buf[MAXCELLCHARS];
667         wchar_t wbuf[MAXCELLCHARS];
668         wchar_t wmethod[KHUI_MAXCCH_NAME];
669         wchar_t * defcells;
670         khm_size cb_defcells;
671         afs_cred_row * r;
672         khm_size sz;
673
674         khc_open_space(csp_params, L"Cells", 0, &h_gcells);
675
676         if (!cm_GetRootCellName(buf) &&
677             afs_check_for_cell_realm_match(ident, buf)) {
678             AnsiStrToUnicode(wbuf, sizeof(wbuf), buf);
679
680             if (afs_check_add_token_to_identity(wbuf, ident, NULL)) {
681                 khm_handle h_cell = NULL;
682
683                 r = afs_cred_get_new_row(l);
684
685                 StringCbLength(wbuf, sizeof(wbuf), &sz);
686                 sz += sizeof(wchar_t);
687
688                 r->cell = PMALLOC(sz);
689                 StringCbCopy(r->cell, sz, wbuf);
690
691                 if (h_gcells &&
692                     KHM_SUCCEEDED(khc_open_space(h_gcells, wbuf, 0, &h_cell))) {
693                     khm_size cb;
694
695                     cb = sizeof(wmethod);
696                     if (KHM_SUCCEEDED(khc_read_string(h_cell, L"MethodName", wmethod, &cb))) {
697                         r->method = afs_get_method_id(wmethod);
698                     } else {
699                         r->method = AFS_TOKEN_AUTO;
700                     }
701
702                     cb = sizeof(wbuf);
703                     if (KHM_SUCCEEDED(khc_read_string(h_cell, L"Realm", wbuf, &cb))) {
704                         r->realm = PMALLOC(cb);
705                         StringCbCopy(r->realm, cb, wbuf);
706                     } else {
707                         r->realm = NULL;
708                     }
709
710                     khc_close_space(h_cell);
711
712                 } else {
713                     r->realm = NULL;
714                     r->method = AFS_TOKEN_AUTO;
715                 }
716
717                 r->flags = 0;
718             }
719         }
720
721         if (khc_read_multi_string(csp_params, L"DefaultCells",
722                                   NULL, &cb_defcells) == KHM_ERROR_TOO_LONG &&
723             cb_defcells > sizeof(wchar_t) * 2) {
724             wchar_t * c_cell;
725
726             defcells = PMALLOC(cb_defcells);
727             if (defcells == NULL)
728                 goto _done_defaults;
729
730             if (KHM_FAILED(khc_read_multi_string(csp_params, L"DefaultCells",
731                                                  defcells, &cb_defcells))) {
732                 PFREE(defcells);
733                 goto _done_defaults;
734             }
735
736             for (c_cell = defcells;
737                  c_cell && *c_cell;
738                  c_cell = multi_string_next(c_cell)) {
739
740                 khm_size cb;
741                 int i;
742                 khm_handle h_cell = NULL;
743                 afs_cred_row * r;
744
745                 if (FAILED(StringCbLength(c_cell, (MAXCELLCHARS + 1) * sizeof(wchar_t),
746                                           &cb)))
747                     continue;
748                 cb += sizeof(wchar_t);
749
750                 for (i=0; i < l->n_rows; i++) {
751                     if (!_wcsicmp(l->rows[i].cell, c_cell))
752                         break;
753                 }
754
755                 if (i < l->n_rows)
756                     continue;
757
758                 {
759                     char cell[MAXCELLCHARS];
760
761                     UnicodeStrToAnsi(cell, sizeof(cell), c_cell);
762
763                     if (!afs_check_for_cell_realm_match(ident, cell))
764                         continue;
765                 }
766
767                 r = afs_cred_get_new_row(l);
768
769                 r->cell = PMALLOC(cb);
770                 StringCbCopy(r->cell, cb, c_cell);
771
772                 if (h_gcells &&
773                     KHM_SUCCEEDED(khc_open_space(h_gcells, c_cell, 0, &h_cell))) {
774
775                     cb = sizeof(wmethod);
776                     if (KHM_SUCCEEDED(khc_read_string(h_cell, L"MethodName", wmethod, &cb))) {
777                         r->method = afs_get_method_id(wmethod);
778                     } else {
779                         r->method = AFS_TOKEN_AUTO;
780                     }
781
782                     cb = sizeof(wbuf);
783                     if (KHM_SUCCEEDED(khc_read_string(h_cell, L"Realm", wbuf, &cb))) {
784                         r->realm = PMALLOC(cb);
785                         StringCbCopy(r->realm, cb, wbuf);
786                     } else {
787                         r->realm = NULL;
788                     }
789
790                     khc_close_space(h_cell);
791                 } else {
792                     r->realm = NULL;
793                     r->method = AFS_TOKEN_AUTO;
794                 }
795
796                 r->flags = 0;
797             }
798
799             PFREE(defcells);
800         }
801     }
802
803  _done_defaults:
804
805     ts.ident = ident;
806     ts.l = l;
807     ts.add_new = TRUE;
808     ts.update_info = FALSE;
809
810     kcdb_credset_apply(NULL, afs_get_id_creds_apply_proc,
811                        &ts);
812
813     if(h_id)
814         khc_close_space(h_id);
815     if(h_afs)
816         khc_close_space(h_afs);
817     if(h_cells)
818         khc_close_space(h_cells);
819     if(h_gcells)
820         khc_close_space(h_gcells);
821 }
822
823 void 
824 nc_dlg_enable(HWND hwnd, BOOL enable) {
825     if(enable) {
826         SendDlgItemMessage(hwnd, IDC_NCAFS_OBTAIN, BM_SETCHECK, 
827                            BST_CHECKED, 0);
828     } else {
829         SendDlgItemMessage(hwnd, IDC_NCAFS_OBTAIN, BM_SETCHECK, 
830                            BST_UNCHECKED, 0);
831     }
832
833     EnableWindow(GetDlgItem(hwnd,IDC_NCAFS_CELL), enable);
834     EnableWindow(GetDlgItem(hwnd,IDC_NCAFS_REALM), enable);
835     EnableWindow(GetDlgItem(hwnd,IDC_NCAFS_METHOD), enable);
836     EnableWindow(GetDlgItem(hwnd,IDC_NCAFS_TOKENLIST), enable);
837     EnableWindow(GetDlgItem(hwnd,IDC_NCAFS_ADD_TOKEN), enable);
838     EnableWindow(GetDlgItem(hwnd,IDC_NCAFS_DELETE_TOKEN), enable);
839 }
840
841 void 
842 nc_dlg_show_tooltip(HWND hwnd, 
843                     UINT_PTR id, 
844                     LPWSTR msg, 
845                     LPWSTR title, 
846                     int type, 
847                     int x, 
848                     int y)
849 {
850     afs_dlg_data * d;
851     TOOLINFO ti;
852
853     d = (afs_dlg_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER);
854
855     ZeroMemory(&ti, sizeof(ti));
856     ti.cbSize = sizeof(ti);
857     ti.hwnd = hwnd;
858     ti.uId = id;
859     SendMessage(d->tooltip, TTM_GETTOOLINFO, 0, (LPARAM) &ti);
860
861     ti.hinst = hResModule;
862     ti.lpszText = msg;
863
864     SendMessage(d->tooltip, TTM_SETTOOLINFO, 0, (LPARAM) &ti);
865
866     if(IS_INTRESOURCE(title)) {
867         wchar_t wbuf[1024];
868         UINT resid;
869
870         resid = (UINT)(UINT_PTR) title;
871
872         LoadString(hResModule, resid, wbuf, ARRAYLENGTH(wbuf));
873         SendMessage(d->tooltip, TTM_SETTITLE, type, (LPARAM) wbuf);
874     } else
875         SendMessage(d->tooltip, TTM_SETTITLE, type, (LPARAM) title);
876
877     SendMessage(d->tooltip, TTM_TRACKACTIVATE, TRUE, (LPARAM) &ti);
878     SendMessage(d->tooltip, TTM_TRACKPOSITION, 0, (LPARAM) MAKELONG(x,y));
879
880     d->tooltip_visible = TRUE;
881
882     SetTimer(hwnd, DLG_TOOLTIP_TIMER_ID, DLG_TOOLTIP_TIMEOUT, NULL);
883 }
884
885 void 
886 nc_dlg_hide_tooltip(HWND hwnd, UINT_PTR id)
887 {
888     TOOLINFO ti;
889     afs_dlg_data * d;
890
891     d = (afs_dlg_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER);
892
893     if(!d->tooltip_visible)
894         return;
895
896     ZeroMemory(&ti, sizeof(ti));
897     ti.cbSize = sizeof(ti);
898     ti.hwnd = hwnd;
899     ti.uId = id;
900
901     SendMessage(d->tooltip, TTM_TRACKACTIVATE, FALSE, (LPARAM) &ti);
902     d->tooltip_visible = FALSE;
903 }
904
905 void 
906 afs_dlg_update_rows(HWND hwnd, afs_dlg_data * d) {
907     HWND hwlist;
908     LVITEM lvi;
909     wchar_t wauto[256];
910     int i;
911
912     CheckDlgButton(hwnd, IDC_NCAFS_OBTAIN,
913                    (d->afs_enabled)? BST_CHECKED: BST_UNCHECKED);
914
915     hwlist = GetDlgItem(hwnd, IDC_NCAFS_TOKENLIST);
916
917     ListView_DeleteAllItems(hwlist);
918
919     if(d->creds.n_rows == 0)
920         return;
921
922     LoadString(hResModule, IDS_NC_AUTO, wauto, ARRAYLENGTH(wauto));
923
924     for(i=0; i < d->creds.n_rows; i++) {
925         wchar_t wbuf[256];
926         int flags;
927
928         ZeroMemory(&lvi, sizeof(lvi));
929
930         lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
931         lvi.iItem = d->creds.n_rows + 1;
932
933         lvi.stateMask = LVIS_STATEIMAGEMASK;
934         flags = d->creds.rows[i].flags;
935         if ((flags & DLGROW_FLAG_EXISTS) &&
936             (flags & DLGROW_FLAG_NOTOWNED)) {
937             lvi.state = INDEXTOSTATEIMAGEMASK(d->idx_bad_token);
938         } else if ((flags & DLGROW_FLAG_EXISTS)) {
939             lvi.state = INDEXTOSTATEIMAGEMASK(d->idx_existing_token);
940         } else {
941             lvi.state = INDEXTOSTATEIMAGEMASK(d->idx_new_token);
942         }
943
944         lvi.lParam = (LPARAM) i;
945
946         lvi.iSubItem = NCAFS_IDX_CELL;
947         lvi.pszText = d->creds.rows[i].cell;
948
949         lvi.iItem = ListView_InsertItem(hwlist, &lvi);
950
951         lvi.mask = LVIF_TEXT; /* subitems dislike lParam */
952         lvi.iSubItem = NCAFS_IDX_REALM;
953         if(d->creds.rows[i].realm != NULL)
954             lvi.pszText = d->creds.rows[i].realm;
955         else
956             lvi.pszText = wauto;
957         ListView_SetItem(hwlist, &lvi);
958
959         lvi.iSubItem = NCAFS_IDX_METHOD;
960         afs_method_describe(d->creds.rows[i].method,
961                             KCDB_TS_SHORT,
962                             wbuf, sizeof(wbuf));
963         lvi.pszText = wbuf;
964
965         ListView_SetItem(hwlist, &lvi);
966     }
967 }
968
969 void 
970 nc_dlg_del_token(HWND hwnd) {
971     afs_dlg_data * d;
972     khui_new_creds_by_type * nct;
973
974     d = (afs_dlg_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER);
975
976     if (d->nc)
977         khui_cw_find_type(d->nc, afs_credtype_id, &nct);
978
979     if(ListView_GetSelectedCount(GetDlgItem(hwnd, IDC_NCAFS_TOKENLIST)) == 0) {
980         wchar_t cell[KCDB_MAXCCH_NAME];
981         int i;
982
983         /* nothing is selected in the list view */
984         /* we delete the row that matches the current contents of the
985         cell edit control */
986         cell[0] = 0;
987         GetDlgItemText(hwnd, IDC_NCAFS_CELL, cell, ARRAYLENGTH(cell));
988         for(i=0; i<d->creds.n_rows; i++) {
989             if(!_wcsicmp(d->creds.rows[i].cell, cell)) {
990                 /* found it */
991                 afs_cred_delete_row(&d->creds, i);
992                 afs_dlg_update_rows(hwnd, d);
993                 d->dirty = TRUE;
994                 break;
995             }
996         }
997     } else {
998         /* something is selected in the token list view */
999         /* we delete that */
1000         HWND hw;
1001         LVITEM lvi;
1002         int idx;
1003         int row;
1004         BOOL deleted = FALSE;
1005
1006         hw = GetDlgItem(hwnd, IDC_NCAFS_TOKENLIST);
1007         idx = -1;
1008         do {
1009             idx = ListView_GetNextItem(hw, idx, LVNI_SELECTED);
1010             if(idx >= 0) {
1011                 ZeroMemory(&lvi, sizeof(lvi));
1012                 lvi.iItem = idx;
1013                 lvi.iSubItem = 0;
1014                 lvi.mask = LVIF_PARAM;
1015                 if(!ListView_GetItem(hw, &lvi))
1016                     continue;
1017                 row = (int) lvi.lParam;
1018                 if(row >= 0 && row < d->creds.n_rows) {
1019                     d->creds.rows[row].flags |= DLGROW_FLAG_DELETED;
1020                     deleted = TRUE;
1021                 }
1022             }
1023         } while(idx != -1);
1024
1025         if(deleted) {
1026             for(idx = 0; idx < d->creds.n_rows; idx ++) {
1027                 if(d->creds.rows[idx].flags & DLGROW_FLAG_DELETED) {
1028                     afs_cred_delete_row(&d->creds, idx);
1029                     idx--; /* we have to look at the current item again */
1030                 }
1031             }
1032
1033             d->dirty = TRUE;
1034             afs_dlg_update_rows(hwnd, d);
1035         }
1036     }
1037
1038     if (d->nc)
1039         SendMessage(d->nc->hwnd, KHUI_WM_NC_NOTIFY, 
1040                     MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), 0);
1041     else if (d->config_dlg && d->dirty)
1042         khui_cfg_set_flags_inst(&d->cfg, KHUI_CNFLAG_MODIFIED,
1043                                 KHUI_CNFLAG_MODIFIED);
1044 }
1045
1046 void 
1047 nc_dlg_add_token(HWND hwnd) {
1048     afs_dlg_data * d;
1049     afs_cred_row * prow;
1050     afs_cred_row trow;
1051     khui_new_creds_by_type * nct;
1052     wchar_t buf[256];
1053     int idx;
1054     size_t n;
1055     size_t cb;
1056     int i;
1057     BOOL new_row = FALSE;
1058     khm_handle ident = NULL;
1059
1060     d = (afs_dlg_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER);
1061
1062     if (d->nc)
1063         khui_cw_find_type(d->nc, afs_credtype_id, &nct);
1064     else
1065         nct = NULL;
1066
1067     if((n = SendDlgItemMessage(hwnd, IDC_NCAFS_CELL, WM_GETTEXT, 
1068                                (WPARAM) ARRAYLENGTH(buf), (LPARAM) buf)) 
1069        == 0)
1070     {
1071         /* probably should indicate that user should type something */
1072         RECT r;
1073         GetWindowRect(GetDlgItem(hwnd, IDC_NCAFS_CELL), &r);
1074         nc_dlg_show_tooltip(hwnd, 
1075                             0, 
1076                             MAKEINTRESOURCE(IDS_NC_TT_NO_CELL), 
1077                             MAKEINTRESOURCE(IDS_NC_TT_CANT_ADD), 
1078                             2, (r.left + r.right)/ 2, r.bottom);
1079         return;
1080     }
1081
1082     if(n != wcsspn(buf, AFS_VALID_CELL_CHARS)) {
1083         RECT r;
1084         GetWindowRect(GetDlgItem(hwnd, IDC_NCAFS_CELL), &r);
1085         nc_dlg_show_tooltip(hwnd, 
1086                             0, 
1087                             MAKEINTRESOURCE(IDS_NC_TT_MALFORMED_CELL), 
1088                             MAKEINTRESOURCE(IDS_NC_TT_CANT_ADD), 
1089                             2, (r.left + r.right)/2, r.bottom);
1090         return;
1091     }
1092
1093     /* check if this is already listed */
1094     for(i=0;i<d->creds.n_rows;i++) {
1095         if(!_wcsicmp(buf, d->creds.rows[i].cell))
1096             break;
1097     }
1098
1099     if(i < d->creds.n_rows) {
1100         new_row = FALSE;
1101
1102         prow = &(d->creds.rows[i]);
1103     } else {
1104         new_row = TRUE;
1105         prow = NULL;
1106     }
1107
1108     ZeroMemory(&trow, sizeof(trow));
1109
1110     cb = (n+1) * sizeof(wchar_t);
1111     trow.cell = PMALLOC(cb);
1112     StringCbCopy(trow.cell, cb, buf);
1113
1114     /* now for the realm */
1115     do {
1116         idx = (int) SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, 
1117                                        CB_GETCURSEL, 0, 0);
1118         if(idx != CB_ERR) {
1119             int lp;
1120             lp = (int) SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, 
1121                                           CB_GETITEMDATA, idx, 0);
1122             if(lp != CB_ERR && lp) /* this is the 'determine realm
1123                                       automatically' item */
1124             {
1125                 trow.realm = NULL;
1126                 break;
1127             }
1128         }
1129
1130         if((n = SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, WM_GETTEXT, 
1131                                    ARRAYLENGTH(buf), (LPARAM) buf)) == 0) {
1132             RECT r;
1133             GetWindowRect(GetDlgItem(hwnd, IDC_NCAFS_REALM), &r);
1134             nc_dlg_show_tooltip(hwnd, 
1135                                 0, 
1136                                 MAKEINTRESOURCE(IDS_NC_TT_NO_REALM), 
1137                                 MAKEINTRESOURCE((new_row)?
1138                                                 IDS_NC_TT_CANT_ADD:
1139                                                 IDS_NC_TT_CANT_UPDATE),
1140                                 2, (r.left + r.right)/2, r.bottom);
1141             goto _error_exit;
1142         }
1143
1144         if(n != wcsspn(buf, AFS_VALID_REALM_CHARS)) {
1145             RECT r;
1146             GetWindowRect(GetDlgItem(hwnd, IDC_NCAFS_REALM), &r);
1147             nc_dlg_show_tooltip(hwnd,
1148                                 0, 
1149                                 MAKEINTRESOURCE(IDS_NC_TT_MALFORMED_REALM),
1150                                 MAKEINTRESOURCE((new_row)?
1151                                                 IDS_NC_TT_CANT_ADD:
1152                                                 IDS_NC_TT_CANT_UPDATE), 
1153                                 2, (r.left + r.right)/2, r.bottom);
1154             goto _error_exit;
1155         }
1156
1157         cb = (n+1) * sizeof(wchar_t);
1158         trow.realm = PMALLOC(cb);
1159         StringCbCopy(trow.realm, cb, buf);
1160
1161     } while(FALSE);
1162
1163     idx = (int)SendDlgItemMessage(hwnd, IDC_NCAFS_METHOD, 
1164                                   CB_GETCURSEL, 0, 0);
1165     if (idx != CB_ERR) {
1166         trow.method = (afs_tk_method)
1167             SendDlgItemMessage(hwnd, IDC_NCAFS_METHOD, CB_GETITEMDATA, 
1168                                idx, 0);
1169     } else {
1170         trow.method = AFS_TOKEN_AUTO;
1171     }
1172
1173     if (d->nc &&
1174         d->nc->n_identities > 0 &&
1175         d->nc->identities[0]) {
1176         
1177         ident = d->nc->identities[0];
1178
1179     } else if (d->ident) {
1180
1181         ident = d->ident;
1182         
1183     }
1184
1185     if(new_row) {
1186         khm_boolean ok_to_add = TRUE;
1187
1188         if (ident) {
1189             khm_handle id_conf = NULL;
1190
1191             ok_to_add =
1192                 afs_check_add_token_to_identity(trow.cell,
1193                                                 ident,
1194                                                 &id_conf);
1195
1196             if (!ok_to_add) {
1197 #if KH_VERSION_API >= 5
1198                 khui_alert * a;
1199                 wchar_t wbuf[512];
1200                 wchar_t wfmt[128];
1201                 wchar_t widname[KCDB_IDENT_MAXCCH_NAME];
1202                 khm_size cb;
1203
1204 #ifdef DEBUG
1205                 assert(id_conf);
1206 #endif
1207                 khui_alert_create_empty(&a);
1208
1209                 cb = sizeof(widname);
1210                 kcdb_identity_get_name(id_conf, widname, &cb);
1211
1212                 LoadString(hResModule, IDS_NC_TT_CONFLICT,
1213                            wfmt, ARRAYLENGTH(wfmt));
1214                 StringCbPrintf(wbuf, sizeof(wbuf),
1215                                wfmt, trow.cell, widname);
1216                 khui_alert_set_message(a, wbuf);
1217
1218                 LoadString(hResModule, IDS_NC_TT_PROBLEM,
1219                            wbuf, ARRAYLENGTH(wbuf));
1220                 khui_alert_set_title(a, wbuf);
1221
1222                 khui_alert_add_command(a, KHUI_PACTION_KEEP);
1223                 khui_alert_add_command(a, KHUI_PACTION_REMOVE);
1224                 khui_alert_add_command(a, KHUI_PACTION_CANCEL);
1225
1226                 khui_alert_set_severity(a, KHERR_INFO);
1227
1228                 khui_alert_show_modal(a);
1229
1230                 ok_to_add = TRUE;
1231
1232                 if (a->response == KHUI_PACTION_REMOVE) {
1233                     afs_remove_token_from_identities(trow.cell);
1234                 } else if (a->response == KHUI_PACTION_CANCEL) {
1235                     ok_to_add = FALSE;
1236                 }
1237
1238                 khui_alert_release(a);
1239 #else
1240                 wchar_t widname[KCDB_IDENT_MAXCCH_NAME];
1241                 wchar_t wtitle[64];
1242                 wchar_t wmsg[512];
1243                 wchar_t wfmt[128];
1244                 khm_size cb;
1245                 int r;
1246
1247 #ifdef DEBUG
1248                 assert(id_conf);
1249 #endif
1250
1251                 cb = sizeof(widname);
1252                 kcdb_identity_get_name(id_conf, widname, &cb);
1253                 LoadString(hResModule, IDS_NC_TT_PROBLEM,
1254                            wtitle, ARRAYLENGTH(wtitle));
1255                 LoadString(hResModule, IDS_NC_TT_CONFLICTM,
1256                            wfmt, ARRAYLENGTH(wfmt));
1257                 StringCbPrintf(wmsg, sizeof(wmsg), wfmt,
1258                                trow.cell, widname);
1259                 r = MessageBox(NULL, wmsg, wtitle,
1260                                MB_YESNOCANCEL | MB_ICONWARNING |
1261                                MB_APPLMODAL);
1262
1263                 ok_to_add = TRUE;
1264                 if (r == IDNO) {
1265                     afs_remove_token_from_identities(trow.cell);
1266                 } else if (r == IDCANCEL) {
1267                     ok_to_add = FALSE;
1268                 }
1269 #endif
1270
1271                 kcdb_identity_release(id_conf);
1272             }
1273
1274             if (!ok_to_add)
1275                 goto _error_exit;
1276         }
1277
1278         prow = afs_cred_get_new_row(&d->creds);
1279     } else {
1280         if (prow->cell)
1281             PFREE(prow->cell);
1282
1283         if(prow->realm)
1284             PFREE(prow->realm);
1285
1286         ZeroMemory(prow, sizeof(*prow));
1287     }
1288
1289     *prow = trow;
1290
1291     if (ident) {
1292         afs_ident_token_set ts;
1293
1294         ts.ident = ident;
1295         ts.l = &d->creds;
1296         ts.add_new = FALSE;
1297         ts.update_info = FALSE;
1298
1299         kcdb_credset_apply(NULL, afs_get_id_creds_apply_proc,
1300                            &ts);
1301     }
1302
1303     afs_dlg_update_rows(hwnd, d);
1304
1305     d->dirty = TRUE;
1306
1307     if (d->nc)
1308         SendMessage(d->nc->hwnd, KHUI_WM_NC_NOTIFY, 
1309                     MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), 0);
1310     else if (d->config_dlg) {
1311         khui_cfg_set_flags_inst(&d->cfg,
1312                                 KHUI_CNFLAG_MODIFIED,
1313                                 KHUI_CNFLAG_MODIFIED);
1314     }
1315
1316     return;
1317
1318 _error_exit:
1319     if(trow.realm)
1320         PFREE(trow.realm);
1321     if(trow.cell)
1322         PFREE(trow.cell);
1323 }
1324
1325 /* this is shared between the new credentials window and the AFS per
1326    identity configuration dialog. */
1327 INT_PTR CALLBACK 
1328 afs_dlg_proc(HWND hwnd,
1329              UINT uMsg,
1330              WPARAM wParam,
1331              LPARAM lParam)
1332 {
1333     switch(uMsg) {
1334     case WM_INITDIALOG:
1335         {
1336             HWND hw;
1337             HIMAGELIST hw_ilist;
1338             afs_dlg_data * d;
1339             khui_new_creds_by_type * nct = NULL;
1340             RECT r;
1341
1342             d = PMALLOC(sizeof(*d));
1343             ZeroMemory(d, sizeof(*d));
1344
1345             InitializeCriticalSection(&d->cs);
1346
1347             /* lParam is a pointer to a khui_new_creds structure */
1348             d->nc = (khui_new_creds *) lParam;
1349
1350             if (d->nc)
1351                 khui_cw_find_type(d->nc, afs_credtype_id, &nct);
1352
1353 #pragma warning(push)
1354 #pragma warning(disable: 4244)
1355             SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM) d);
1356 #pragma warning(pop)
1357
1358             EnterCriticalSection(&d->cs);
1359
1360             if (nct)
1361                 nct->aux = (LPARAM) d;
1362
1363             /* create the tooltip window */
1364             d->tooltip = 
1365                 CreateWindowEx(WS_EX_TOPMOST,
1366                                TOOLTIPS_CLASS,
1367                                NULL,
1368                                WS_POPUP | TTS_BALLOON | TTS_ALWAYSTIP,
1369                                CW_USEDEFAULT, CW_USEDEFAULT,
1370                                CW_USEDEFAULT, CW_USEDEFAULT,
1371                                hwnd,  /* make this an owned window, so
1372                                          we don't have to worry about
1373                                          destroying it */
1374                                NULL,
1375                                hInstance,
1376                                NULL);
1377
1378             SetWindowPos(d->tooltip,
1379                          HWND_TOPMOST,
1380                          0,
1381                          0,
1382                          0,
1383                          0,
1384                          SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
1385
1386             {
1387                 TOOLINFO ti;
1388
1389                 ZeroMemory(&ti, sizeof(ti));
1390                 ti.cbSize = sizeof(ti);
1391                 ti.uFlags = TTF_TRACK;
1392                 ti.hwnd = hwnd;
1393                 ti.uId = 0;
1394                 ti.hinst = hResModule;
1395                 ti.lpszText = L"";
1396                 GetClientRect(hwnd, &(ti.rect));
1397
1398                 SendMessage(d->tooltip, TTM_ADDTOOL, 0, (LPARAM) &ti);
1399             }
1400
1401             /* we only initialize the constant bits here. */
1402             hw = GetDlgItem(hwnd, IDC_NCAFS_TOKENLIST);
1403
1404             GetClientRect(hw, &r);
1405
1406             /* set the list view status icons */
1407             hw_ilist = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
1408                                         GetSystemMetrics(SM_CYSMICON),
1409                                         ILC_COLOR8 | ILC_MASK,
1410                                         4, 4);
1411 #ifdef DEBUG
1412             assert(hw_ilist);
1413 #endif
1414             {
1415                 HICON hi;
1416
1417                 hi = LoadImage(hResModule, MAKEINTRESOURCE(IDI_NC_NEW),
1418                                IMAGE_ICON,
1419                                GetSystemMetrics(SM_CXSMICON),
1420                                GetSystemMetrics(SM_CYSMICON),
1421                                LR_DEFAULTCOLOR);
1422
1423                 d->idx_new_token = ImageList_AddIcon(hw_ilist, hi) + 1;
1424
1425                 DestroyIcon(hi);
1426
1427                 hi = LoadImage(hResModule, MAKEINTRESOURCE(IDI_NC_EXIST),
1428                                IMAGE_ICON,
1429                                GetSystemMetrics(SM_CXSMICON),
1430                                GetSystemMetrics(SM_CYSMICON),
1431                                LR_DEFAULTCOLOR);
1432                 d->idx_existing_token = ImageList_AddIcon(hw_ilist, hi) + 1;
1433
1434                 DestroyIcon(hi);
1435
1436                 hi = LoadImage(hResModule,
1437                                MAKEINTRESOURCE(IDI_NC_NOTOWNED),
1438                                IMAGE_ICON,
1439                                GetSystemMetrics(SM_CXSMICON),
1440                                GetSystemMetrics(SM_CYSMICON),
1441                                LR_DEFAULTCOLOR);
1442                 d->idx_bad_token = ImageList_AddIcon(hw_ilist, hi) + 1 ;
1443
1444                 DestroyIcon(hi);
1445             }
1446
1447             ListView_SetImageList(hw, hw_ilist, LVSIL_STATE);
1448
1449             ListView_DeleteAllItems(hw);
1450
1451             /* set the columns */
1452             {
1453                 LVCOLUMN lc;
1454                 wchar_t wbuf[256];
1455
1456                 lc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT;
1457                 lc.fmt = LVCFMT_LEFT;
1458                 lc.cx = ((r.right - r.left) * 2) / 5;
1459                 LoadString(hResModule, IDS_NCAFS_COL_CELL, 
1460                            wbuf, ARRAYLENGTH(wbuf));
1461                 lc.pszText = wbuf;
1462
1463                 ListView_InsertColumn(hw, 0, &lc);
1464
1465                 lc.mask |= LVCF_SUBITEM;
1466                 //lc.cx is the same as above
1467                 lc.iSubItem = NCAFS_IDX_REALM;
1468                 LoadString(hResModule, IDS_NCAFS_COL_REALM, 
1469                            wbuf, ARRAYLENGTH(wbuf));
1470
1471                 ListView_InsertColumn(hw, 1, &lc);
1472
1473                 lc.cx = ((r.right - r.left) * 1) / 5;
1474                 lc.iSubItem = NCAFS_IDX_METHOD;
1475                 LoadString(hResModule, IDS_NCAFS_COL_METHOD, 
1476                            wbuf, ARRAYLENGTH(wbuf));
1477
1478                 ListView_InsertColumn(hw, 2, &lc);
1479             }
1480
1481             /* Set the items for the 'method' combo box */
1482             hw = GetDlgItem(hwnd, IDC_NCAFS_METHOD);
1483
1484             {
1485                 wchar_t wbuf[KHUI_MAXCB_SHORT_DESC];
1486                 afs_tk_method method = -1;
1487                 int idx;
1488
1489                 SendMessage(hw, CB_RESETCONTENT, 0, 0);
1490
1491                 while((method = afs_get_next_method_id(method)) >= 0) {
1492                     afs_method_describe(method, KCDB_TS_SHORT,
1493                                         wbuf, sizeof(wbuf));
1494                     idx = (int)SendMessage(hw, CB_INSERTSTRING,
1495                                            (WPARAM) -1, (LPARAM) wbuf);
1496 #ifdef DEBUG
1497                     assert(idx != CB_ERR);
1498 #endif
1499                     SendMessage(hw, CB_SETITEMDATA, (WPARAM) idx,
1500                                 (LPARAM)  method);
1501                 }
1502
1503                 /* finally, set the current selection to auto, which
1504                    is the first method returned by
1505                    afs_get_next_method_id() */
1506                 SendMessage(hw, CB_SETCURSEL, 0, 0);
1507             }
1508
1509             d->afs_enabled = TRUE;
1510             SendDlgItemMessage(hwnd, IDC_NCAFS_OBTAIN, 
1511                                BM_SETCHECK, BST_CHECKED, 0);
1512
1513             LeaveCriticalSection(&d->cs);
1514
1515             /* the cells and realms combo boxes need to be filled
1516                in the plugin thread since that requires making
1517                potentially blocking and non-thread safe calls */
1518         }
1519         return TRUE;
1520
1521     case WM_DESTROY:
1522         {
1523             afs_dlg_data * d;
1524             khui_new_creds_by_type * nct;
1525
1526             d = (afs_dlg_data *)(LONG_PTR) 
1527                 GetWindowLongPtr(hwnd, DWLP_USER);
1528
1529             EnterCriticalSection(&d->cs);
1530
1531             if (d->nc) {
1532                 khui_cw_find_type(d->nc, afs_credtype_id, &nct);
1533
1534                 nct->aux = (LPARAM) NULL;
1535             }
1536
1537             afs_cred_free_rows(&d->creds);
1538
1539             LeaveCriticalSection(&d->cs);
1540             DeleteCriticalSection(&d->cs);
1541
1542             PFREE(d);
1543         }
1544         return TRUE;
1545
1546     case WM_COMMAND:
1547         {
1548             afs_dlg_data * d;
1549             khui_new_creds_by_type * nct;
1550
1551             d = (afs_dlg_data *)(LONG_PTR) 
1552                 GetWindowLongPtr(hwnd, DWLP_USER);
1553
1554             EnterCriticalSection(&d->cs);
1555
1556             if (d->nc)
1557                 khui_cw_find_type(d->nc, afs_credtype_id, &nct);
1558             else
1559                 nct = NULL;
1560
1561             nc_dlg_hide_tooltip(hwnd, 0);
1562
1563             /* Handle WM_COMMAND */
1564             switch(wParam) {
1565             case MAKEWPARAM(IDC_NCAFS_OBTAIN, BN_CLICKED):
1566                 {
1567                     BOOL c;
1568                     c = (SendDlgItemMessage(hwnd, IDC_NCAFS_OBTAIN, 
1569                                             BM_GETCHECK, 0, 0) 
1570                          == BST_CHECKED);
1571                     d->afs_enabled = c;
1572                     d->dirty = TRUE;
1573                     if (d->nc)
1574                         khui_cw_enable_type(d->nc, afs_credtype_id, c);
1575                     else if (d->config_dlg)
1576                         khui_cfg_set_flags_inst(&d->cfg,
1577                                                 KHUI_CNFLAG_MODIFIED,
1578                                                 KHUI_CNFLAG_MODIFIED);
1579                     nc_dlg_enable(hwnd, c);
1580                 }
1581                 break;
1582
1583             case MAKEWPARAM(IDC_NCAFS_ADD_TOKEN, BN_CLICKED):
1584                 {
1585                     nc_dlg_add_token(hwnd);
1586                 }
1587                 break;
1588
1589             case MAKEWPARAM(IDC_NCAFS_DELETE_TOKEN, BN_CLICKED):
1590                 {
1591                     nc_dlg_del_token(hwnd);
1592                 }
1593                 break;
1594             }
1595
1596             LeaveCriticalSection(&d->cs);
1597         }
1598         return TRUE;
1599
1600     case KHUI_WM_NC_NOTIFY:
1601         {
1602             afs_dlg_data * d;
1603             khui_new_creds_by_type * nct;
1604
1605             d = (afs_dlg_data *)(LONG_PTR) 
1606                 GetWindowLongPtr(hwnd, DWLP_USER);
1607
1608             EnterCriticalSection(&d->cs);
1609
1610             if (d->nc)
1611                 khui_cw_find_type(d->nc, afs_credtype_id, &nct);
1612             else
1613                 nct = NULL;
1614
1615             switch(HIWORD(wParam)) {
1616             case WMNC_DIALOG_SETUP:
1617                 {
1618                     SendDlgItemMessage(hwnd, IDC_NCAFS_CELL, 
1619                                        CB_RESETCONTENT, 0, 0);
1620                     
1621                     /* load the LRU cells */
1622                     {
1623                         wchar_t * buf;
1624                         wchar_t *s;
1625                         khm_size cbbuf;
1626
1627                         if(khc_read_multi_string(csp_params, L"LRUCells", 
1628                                                  NULL, &cbbuf) == 
1629                            KHM_ERROR_TOO_LONG) {
1630                             buf = PMALLOC(cbbuf);
1631                             khc_read_multi_string(csp_params, L"LRUCells", 
1632                                                   buf, &cbbuf);
1633                             s = buf;
1634                             while(*s) {
1635                                 SendDlgItemMessage(hwnd, IDC_NCAFS_CELL, 
1636                                                    CB_ADDSTRING, 0, (LPARAM) s);
1637                                 s += wcslen(s) + 1;
1638                             }
1639                             PFREE(buf);
1640                         }
1641                     }
1642
1643                     /* now, if the root cell is not in the LRU, add it */
1644                     {
1645                         char buf[256];
1646                         wchar_t wbuf[256];
1647
1648                         if(!cm_GetRootCellName(buf)) {
1649                             AnsiStrToUnicode(wbuf, sizeof(wbuf), buf);
1650                             if(SendDlgItemMessage(hwnd,
1651                                                   IDC_NCAFS_CELL,
1652                                                   CB_FINDSTRINGEXACT,
1653                                                   (WPARAM) -1,
1654                                                   (LPARAM) wbuf) == CB_ERR) {
1655                                 SendDlgItemMessage(hwnd, IDC_NCAFS_CELL, 
1656                                                    CB_ADDSTRING, 
1657                                                    0, (LPARAM) wbuf);
1658                             }
1659                             SendDlgItemMessage(hwnd, IDC_NCAFS_CELL, 
1660                                                CB_SELECTSTRING, 
1661                                                -1, (LPARAM) wbuf);
1662                         }
1663                     }
1664
1665                     SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, 
1666                                        CB_RESETCONTENT, 0, 0);
1667
1668                     /* as for the realms, we have a special one here */
1669                     {
1670                         wchar_t wbuf[256];
1671                         int idx;
1672
1673                         LoadString(hResModule, IDS_NC_REALM_AUTO, wbuf, 
1674                                    (int) ARRAYLENGTH(wbuf));
1675                         idx = (int) SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, 
1676                                                        CB_ADDSTRING, 0, 
1677                                                        (LPARAM) wbuf);
1678                         /* item data for the realm strings is the
1679                            answer to the question, "is this the
1680                            'determine realm automatically' item?" */
1681                         SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, 
1682                                            CB_SETITEMDATA, idx, TRUE);
1683                         SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, 
1684                                            CB_SELECTSTRING, 
1685                                            -1, (LPARAM) wbuf);
1686                     }
1687
1688                     /* load the LRU realms */
1689                     {
1690                         wchar_t * buf;
1691                         wchar_t *s;
1692                         int idx;
1693                         khm_size cbbuf;
1694
1695                         if(khc_read_multi_string(csp_params, L"LRURealms", 
1696                                                  NULL, &cbbuf) == 
1697                            KHM_ERROR_TOO_LONG) {
1698                             buf = PMALLOC(cbbuf);
1699                             khc_read_multi_string(csp_params, L"LRURealms", 
1700                                                   buf, &cbbuf);
1701                             s = buf;
1702                             while(*s) {
1703                                 if(SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, 
1704                                                       CB_FINDSTRINGEXACT, -1, 
1705                                                       (LPARAM) s) == CB_ERR) {
1706                                     idx = 
1707                                         (int)
1708                                         SendDlgItemMessage(hwnd, 
1709                                                            IDC_NCAFS_REALM, 
1710                                                            CB_ADDSTRING, 
1711                                                            0, (LPARAM) s);
1712                                     SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, 
1713                                                        CB_SETITEMDATA, 
1714                                                        idx, FALSE);
1715                                 }
1716
1717                                 s += wcslen(s) + 1;
1718                             }
1719                             PFREE(buf);
1720                         }
1721                     }
1722
1723                     if (d->nc)
1724                         khui_cw_enable_type(d->nc, afs_credtype_id, 
1725                                             d->afs_enabled);
1726
1727                     nc_dlg_enable(hwnd, d->afs_enabled);
1728
1729                     afs_dlg_update_rows(hwnd, d);
1730                 }
1731                 break;
1732
1733             case WMNC_UPDATE_CREDTEXT:
1734                 {
1735                     wchar_t wformat[256];
1736                     wchar_t wstr[2048];
1737                     khm_int32 flags;
1738
1739                     if(nct->credtext) {
1740                         PFREE(nct->credtext);
1741                         nct->credtext = NULL;
1742                     }
1743
1744 #ifdef DEBUG
1745                     assert(d->nc);
1746 #endif
1747
1748                     if (d->nc->n_identities == 0 ||
1749                         KHM_FAILED(kcdb_identity_get_flags(d->nc->identities[0],
1750                                                            &flags)) ||
1751                         !(flags & KCDB_IDENT_FLAG_VALID))
1752                         /* in this case, we don't show any credential text */
1753                         break;
1754
1755                     wstr[0] = 0;
1756
1757                     if(!d->afs_enabled) {
1758                         LoadString(hResModule, IDS_AFS_CREDTEXT_DIS, 
1759                                    wstr, ARRAYLENGTH(wstr));
1760                     } else {
1761                         if(d->creds.n_rows == 0) {
1762                             LoadString(hResModule, IDS_AFS_CREDTEXT_0, 
1763                                        wstr, ARRAYLENGTH(wstr));
1764                         } else if(d->creds.n_rows == 1) {
1765                             LoadString(hResModule, IDS_AFS_CREDTEXT_1, 
1766                                        wformat, ARRAYLENGTH(wformat));
1767                             StringCbPrintf(wstr, sizeof(wstr), wformat, 
1768                                            d->creds.rows[0].cell);
1769                         } else {
1770                             int i;
1771                             wchar_t wcells[1024];
1772
1773                             LoadString(hResModule, IDS_AFS_CREDTEXT_N, 
1774                                        wformat, ARRAYLENGTH(wformat));
1775                             wcells[0] = 0;
1776                             for(i=0; i<d->creds.n_rows; i++) {
1777                                 if(i > 0)
1778                                     StringCbCat(wcells, sizeof(wcells), 
1779                                                 L", ");
1780                                 if(FAILED(StringCbCat(wcells, 
1781                                                       sizeof(wcells), 
1782                                                       d->creds.rows[i].cell))) {
1783                                     size_t cch;
1784                                     /* looks like we overflowed */
1785                                     /* add an ellipsis at the end */
1786                                     StringCchLength(wcells, ARRAYLENGTH(wcells), &cch);
1787                                     cch = min(ARRAYLENGTH(wcells) - 4, cch);
1788                                     StringCchCopy(wcells + cch, 4, L"...");
1789
1790                                     break;
1791                                 }
1792                             }
1793
1794                             StringCbPrintf(wstr, sizeof(wstr), wformat, wcells);
1795                         }
1796                     }
1797
1798                     if(wstr[0] != 0) {
1799                         size_t cbs;
1800                         StringCbLength(wstr, sizeof(wstr), &cbs);
1801                         cbs += sizeof(wchar_t);
1802                         assert(nct->credtext == NULL);
1803                         nct->credtext = PMALLOC(cbs);
1804                         StringCbCopy(nct->credtext, cbs, wstr);
1805                     } else {
1806                         /* something went wrong */
1807                         nct->credtext = NULL;
1808                     }
1809                 }
1810                 break;
1811
1812             case WMNC_CREDTEXT_LINK:
1813                 {
1814                     khui_htwnd_link * l;
1815                     wchar_t wid[KHUI_MAXCCH_HTLINK_FIELD];
1816                     wchar_t * wids;
1817
1818                     l = (khui_htwnd_link *) lParam;
1819
1820                     StringCchCopyN(wid, ARRAYLENGTH(wid), l->id, l->id_len);
1821                     wids = wcschr(wid, L':');
1822                         
1823                     if(!wids)
1824                         break;
1825                     else
1826                         wids++;
1827
1828 #ifdef DEBUG
1829                     assert(d->nc);
1830 #endif
1831
1832                     if(!wcscmp(wids, L"Enable")) {
1833                         SendDlgItemMessage(hwnd, IDC_NCAFS_OBTAIN, 
1834                                            BM_SETCHECK, BST_CHECKED, 0);
1835                         d->afs_enabled = TRUE;
1836                         khui_cw_enable_type(d->nc, afs_credtype_id, TRUE);
1837                         nc_dlg_enable(hwnd, TRUE);
1838                     }
1839                 }
1840                 break;
1841
1842             case WMNC_IDENTITY_CHANGE:
1843                 kmq_post_sub_msg(afs_sub, KMSG_CRED, 
1844                                  KMSG_CRED_DIALOG_NEW_IDENTITY, 0, 
1845                                  (void *) d->nc);
1846                 break;
1847                 
1848             case WMNC_AFS_UPDATE_ROWS:
1849                 afs_dlg_update_rows(hwnd, d);
1850
1851 #ifdef DEBUG
1852                 assert(d->nc);
1853 #endif
1854
1855                 PostMessage(d->nc->hwnd, KHUI_WM_NC_NOTIFY, 
1856                             MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), 0);
1857                 break;
1858             }
1859
1860             LeaveCriticalSection(&d->cs);
1861         }
1862         return TRUE;
1863
1864     case WM_NOTIFY:
1865         if(wParam == IDC_NCAFS_TOKENLIST) {
1866             LPNMHDR lpnmh = (LPNMHDR) lParam;
1867
1868             if(lpnmh->code == LVN_ITEMCHANGED) {
1869                 /* when an item in the list view is clicked, we
1870                    load the corresponding values into the edit and
1871                    combo boxes */
1872                 NMLISTVIEW *lpnmlv = (NMLISTVIEW *) lpnmh;
1873                 LVITEM lvi;
1874                 HWND hw;
1875                 int idx;
1876                 int row;
1877                 afs_dlg_data * d;
1878
1879                 if (!(lpnmlv->uChanged & LVIF_STATE) ||
1880                     !(lpnmlv->uNewState & LVIS_SELECTED) ||
1881                     (lpnmlv->iItem == -1))
1882
1883                     return TRUE;
1884
1885                 d = (afs_dlg_data *)(LONG_PTR) 
1886                     GetWindowLongPtr(hwnd, DWLP_USER);
1887
1888                 EnterCriticalSection(&d->cs);
1889
1890                 hw = GetDlgItem(hwnd, IDC_NCAFS_TOKENLIST);
1891
1892                 idx = lpnmlv->iItem;
1893
1894                 ZeroMemory(&lvi, sizeof(lvi));
1895                 lvi.iItem = idx;
1896                 lvi.iSubItem = 0;
1897                 lvi.mask = LVIF_PARAM;
1898
1899                 if(!ListView_GetItem(hw, &lvi))
1900                     goto _done_notify_select;
1901
1902                 /* ok, now lvi.lParam should be the row of the token */
1903                 row = (int) lvi.lParam;
1904                 if(row < 0 || row >= d->creds.n_rows)
1905                     goto _done_notify_select;
1906
1907                 SetDlgItemText(hwnd, IDC_NCAFS_CELL, 
1908                                d->creds.rows[row].cell);
1909                 if(d->creds.rows[row].realm != NULL) {
1910                     SetDlgItemText(hwnd, IDC_NCAFS_REALM, 
1911                                    d->creds.rows[row].realm);
1912                 } else {
1913                     wchar_t wbuf[256];
1914                     int idx;
1915                         
1916                     LoadString(hResModule, IDS_NC_REALM_AUTO, wbuf, 
1917                                ARRAYLENGTH(wbuf));
1918                     idx = (int) SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, 
1919                                                    CB_FINDSTRINGEXACT, -1, 
1920                                                    (LPARAM) wbuf);
1921                     SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, CB_SETCURSEL,
1922                                        idx, 0);
1923                 }
1924                 SendDlgItemMessage(hwnd, IDC_NCAFS_METHOD, CB_SETCURSEL, 
1925                                    d->creds.rows[row].method, 0);
1926             _done_notify_select:
1927                 LeaveCriticalSection(&d->cs);
1928
1929             } else if (lpnmh->code == NM_DBLCLK) {
1930
1931                 LPNMITEMACTIVATE pnmi;
1932                 LVITEM lvi;
1933                 HWND hw;
1934                 afs_dlg_data * d;
1935                 int row;
1936                 int x,y;
1937                 RECT r;
1938
1939                 d = (afs_dlg_data *)(LONG_PTR) 
1940                     GetWindowLongPtr(hwnd, DWLP_USER);
1941
1942                 EnterCriticalSection(&d->cs);
1943
1944                 pnmi = (LPNMITEMACTIVATE) lpnmh;
1945
1946                 hw = GetDlgItem(hwnd, IDC_NCAFS_TOKENLIST);
1947
1948                 ZeroMemory(&lvi, sizeof(lvi));
1949                 lvi.iItem = pnmi->iItem;
1950                 lvi.iSubItem = 0;
1951                 lvi.mask = LVIF_PARAM;
1952
1953                 if (!ListView_GetItem(hw, &lvi))
1954                     goto _done_notify_click;
1955
1956                 row = (int) lvi.lParam;
1957                 if(row < 0 || row >= d->creds.n_rows)
1958                     goto _done_notify_click;
1959
1960                 ListView_GetItemRect(hw, pnmi->iItem, &r, LVIR_SELECTBOUNDS);
1961                 x = (r.left + r.right) / 2;
1962                 y = (r.bottom);
1963
1964                 GetWindowRect(hw, &r);
1965                 y += r.top;
1966                 x += r.left;
1967
1968                 if (d->creds.rows[row].flags & DLGROW_FLAG_NOTOWNED) {
1969                     nc_dlg_show_tooltip(hwnd, 0,
1970                                         MAKEINTRESOURCE(IDS_NC_TT_CONFLICTD),
1971                                         MAKEINTRESOURCE(IDS_NC_TT_PROBLEM),
1972                                         2,
1973                                         x,y);
1974                 } else if (d->creds.rows[row].flags &
1975                            DLGROW_FLAG_EXPIRED) {
1976                     nc_dlg_show_tooltip(hwnd, 0,
1977                                         MAKEINTRESOURCE(IDS_NC_TT_EXPIRED),
1978                                         MAKEINTRESOURCE(IDS_NC_TT_DETAILS),
1979                                         1,
1980                                         x, y);
1981                 } else if (d->creds.rows[row].flags &
1982                            DLGROW_FLAG_EXISTS) {
1983                     nc_dlg_show_tooltip(hwnd, 0,
1984                                         MAKEINTRESOURCE(IDS_NC_TT_EXISTS),
1985                                         MAKEINTRESOURCE(IDS_NC_TT_DETAILS),
1986                                         1, x, y);
1987                 } else {
1988                     nc_dlg_show_tooltip(hwnd, 0,
1989                                         MAKEINTRESOURCE(IDS_NC_TT_NEW),
1990                                         MAKEINTRESOURCE(IDS_NC_TT_DETAILS),
1991                                         1, x, y);
1992                 }
1993
1994             _done_notify_click:
1995                 LeaveCriticalSection(&d->cs);
1996             }
1997         }
1998         return TRUE;
1999
2000     case WM_TIMER:
2001         {
2002             if(wParam == DLG_TOOLTIP_TIMER_ID) {
2003                 KillTimer(hwnd, DLG_TOOLTIP_TIMER_ID);
2004                 nc_dlg_hide_tooltip(hwnd, 0);
2005             }
2006         }
2007         return TRUE;
2008
2009     case WM_HELP:
2010         {
2011             static const DWORD ctx_help[] = {
2012                 IDC_NCAFS_OBTAIN, IDH_OBTAIN,
2013                 IDC_NCAFS_CELL, IDH_CELL,
2014                 IDC_NCAFS_REALM, IDH_REALM,
2015                 IDC_NCAFS_METHOD, IDH_METHOD,
2016                 IDC_NCAFS_ADD_TOKEN, IDH_ADD,
2017                 IDC_NCAFS_DELETE_TOKEN, IDH_DELETE,
2018                 IDC_NCAFS_TOKENLIST, IDH_TOKENLIST,
2019                 0
2020             };
2021
2022             LPHELPINFO hlp;
2023
2024             hlp = (LPHELPINFO) lParam;
2025
2026             if (hlp->iContextType != HELPINFO_WINDOW)
2027                 break;
2028
2029             afs_html_help(hlp->hItemHandle, L"::/popups_newcred.txt",
2030                           HH_TP_HELP_WM_HELP, (DWORD_PTR) ctx_help);
2031         }
2032         return TRUE;
2033     } /* switch(uMsg) */
2034
2035     return FALSE;
2036 }
2037
2038
2039 /* passed in to kcdb_credset_apply along with the afs_credset to adjust
2040    newly acquired credentials to include informatino derived from the
2041    new creds operation */
2042 khm_int32 KHMAPI 
2043 afs_adjust_token_ident_proc(khm_handle cred, void * vd)
2044 {
2045     wchar_t cell[MAXCELLCHARS];
2046     afs_ident_token_set * b = (afs_ident_token_set *) vd;
2047     afs_cred_list * l;
2048     khm_size cbbuf;
2049     int i;
2050
2051     l = b->l;
2052
2053     /* ASSUMPTION: for each user, there can be tokens for only one
2054        cell */
2055
2056     cbbuf = sizeof(cell);
2057
2058     if(KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_cell, NULL, cell, &cbbuf)))
2059         return KHM_ERROR_SUCCESS; /* remember, kcdb doesn't care if
2060                                      this run succeeded or not.  all
2061                                      it wants to know if whether or
2062                                      not we want to continue the
2063                                      search */
2064     
2065     for(i=0; i<l->n_rows; i++) {
2066         if((l->rows[i].flags & DLGROW_FLAG_DONE) && 
2067            !_wcsicmp(cell, l->rows[i].cell)) {
2068             khm_int32 method;
2069
2070             kcdb_cred_set_identity(cred, b->ident);
2071             if(l->rows[i].realm)
2072                 kcdb_cred_set_attr(cred, afs_attr_realm, l->rows[i].realm, 
2073                                    KCDB_CBSIZE_AUTO);
2074             else
2075                 kcdb_cred_set_attr(cred, afs_attr_realm, NULL, 0);
2076
2077             method = l->rows[i].method;
2078             kcdb_cred_set_attr(cred, afs_attr_method, &method, 
2079                                KCDB_CBSIZE_AUTO);
2080
2081             break;
2082         }
2083     }
2084
2085     return KHM_ERROR_SUCCESS;
2086 }
2087
2088 void
2089 afs_cred_write_ident_data(afs_dlg_data * d) {
2090     wchar_t * lru_cell = NULL;
2091     wchar_t * lru_realm = NULL;
2092     wchar_t * id_cell = NULL;
2093     khm_size cbidcell;
2094     khm_size cbcell;
2095     khm_size cbrealm;
2096     khm_size cbt;
2097     size_t cbz;
2098     khm_handle h_idc = NULL;
2099     khm_handle h_afs = NULL;
2100     khm_handle h_acells = NULL;
2101     khm_handle h_cellmap = NULL;
2102     wchar_t idname[KCDB_IDENT_MAXCCH_NAME];
2103     khm_handle ident = NULL;
2104     afs_cred_list * l;
2105     int i;
2106
2107     l = &d->creds;
2108
2109     if (d->nc &&
2110         d->nc->n_identities > 0 &&
2111         d->nc->identities[0])
2112
2113         ident = d->nc->identities[0];
2114
2115     else if (d->config_dlg)
2116
2117         ident = d->ident;
2118
2119     if (!ident)
2120         return;
2121
2122     cbt = sizeof(idname);
2123     kcdb_identity_get_name(ident, idname, &cbt);
2124
2125     khc_open_space(csp_afscred, L"Cells", 0, &h_cellmap);
2126
2127     if(ident) {
2128         if(KHM_SUCCEEDED(kcdb_identity_get_config(ident,
2129                                                   KHM_FLAG_CREATE,
2130                                                   &h_idc))) {
2131             khc_open_space(h_idc, CSNAME_AFSCRED, 
2132                            KHM_FLAG_CREATE, &h_afs);
2133         }
2134
2135         if(h_afs) {
2136             khc_open_space(h_afs, L"Cells", KHM_FLAG_CREATE, 
2137                            &h_acells);
2138         }
2139     }
2140
2141     if (h_afs && d) {
2142         khc_write_int32(h_afs, L"AFSEnabled",
2143                         !!d->afs_enabled);
2144     }
2145
2146     if(khc_read_multi_string(csp_params, 
2147                              L"LRUCells", 
2148                              NULL,
2149                              &cbcell) == KHM_ERROR_TOO_LONG) {
2150         cbcell += MAXCELLCHARS * sizeof(wchar_t) * 
2151             l->n_rows;
2152         lru_cell = PMALLOC(cbcell);
2153         ZeroMemory(lru_cell, cbcell);
2154         cbt = cbcell;
2155                     
2156         khc_read_multi_string(csp_params,
2157                               L"LRUCells",
2158                               lru_cell,
2159                               &cbt);
2160     } else {
2161         cbcell = MAXCELLCHARS * sizeof(wchar_t) * 
2162             l->n_rows;
2163         if (cbcell > 0) {
2164             lru_cell = PMALLOC(cbcell);
2165             ZeroMemory(lru_cell, cbcell);
2166         } else {
2167             lru_cell = NULL;
2168         }
2169     }
2170
2171     if(khc_read_multi_string(csp_params,
2172                              L"LRURealms",
2173                              NULL,
2174                              &cbrealm) == KHM_ERROR_TOO_LONG) {
2175         cbrealm += MAXCELLCHARS * sizeof(wchar_t) * l->n_rows;
2176         lru_realm = PMALLOC(cbrealm);
2177         ZeroMemory(lru_realm, cbrealm);
2178         cbt = cbrealm;
2179
2180         khc_read_multi_string(csp_params,
2181                               L"LRURealms",
2182                               lru_realm,
2183                               &cbt);
2184     } else {
2185         cbrealm = MAXCELLCHARS * sizeof(wchar_t) * l->n_rows;
2186         if (cbrealm > 0) {
2187             lru_realm = PMALLOC(cbrealm);
2188             ZeroMemory(lru_realm, cbrealm);
2189         } else {
2190             lru_cell = NULL;
2191         }
2192     }
2193
2194     cbidcell = MAXCELLCHARS * sizeof(wchar_t) * l->n_rows;
2195     if (cbidcell > 0) {
2196         id_cell = PMALLOC(cbidcell);
2197         ZeroMemory(id_cell, cbidcell);
2198     } else {
2199         id_cell = NULL;
2200     }
2201
2202     for(i=0; i < l->n_rows; i++)
2203         if(!(l->rows[i].flags & DLGROW_FLAG_DELETED)) {
2204             khm_handle h_acell = NULL;
2205             
2206             if(!multi_string_find(lru_cell, 
2207                                   l->rows[i].cell, 0)) {
2208                 cbz = cbcell;
2209                 multi_string_append(lru_cell, &cbz, 
2210                                     l->rows[i].cell);
2211             }
2212
2213             if(l->rows[i].realm && 
2214                !multi_string_find(lru_realm, 
2215                                   l->rows[i].realm, 0)) {
2216                 cbz = cbrealm;
2217                 multi_string_append(lru_realm, &cbz, 
2218                                     l->rows[i].realm);
2219             }
2220
2221             cbz = cbidcell;
2222             multi_string_append(id_cell, &cbz, 
2223                                 l->rows[i].cell);
2224
2225             if(h_acells && 
2226                KHM_SUCCEEDED(khc_open_space(h_acells, 
2227                                             l->rows[i].cell, 
2228                                             KHM_FLAG_CREATE, 
2229                                             &h_acell))) {
2230                 wchar_t methodname[KHUI_MAXCCH_NAME];
2231
2232                 afs_get_method_name(l->rows[i].method,
2233                                     methodname,
2234                                     sizeof(methodname));
2235
2236                 khc_write_string(h_acell, L"MethodName", 
2237                                  methodname);
2238
2239                 if(l->rows[i].realm)
2240                     khc_write_string(h_acell, L"Realm", 
2241                                      l->rows[i].realm);
2242                 else
2243                     khc_write_string(h_acell, L"Realm", L"");
2244                 khc_close_space(h_acell);
2245             }
2246
2247             if (h_cellmap) {
2248                 khc_write_string(h_cellmap,
2249                                  l->rows[i].cell,
2250                                  idname);
2251             }
2252         }
2253
2254     if (lru_cell)                
2255         khc_write_multi_string(csp_params,
2256                                L"LRUCells", lru_cell);
2257     if (lru_realm)
2258         khc_write_multi_string(csp_params,
2259                                L"LRURealms", lru_realm);
2260     if (id_cell)
2261         khc_write_multi_string(h_afs, L"Cells",
2262                                id_cell);
2263
2264     if (d->config_dlg) {
2265         if (d->dirty)
2266             khui_cfg_set_flags_inst(&d->cfg, KHUI_CNFLAG_APPLIED,
2267                                     KHUI_CNFLAG_APPLIED |
2268                                     KHUI_CNFLAG_MODIFIED);
2269         else
2270             khui_cfg_set_flags_inst(&d->cfg, 0,
2271                                     KHUI_CNFLAG_MODIFIED);
2272     }
2273
2274     d->dirty = FALSE;
2275
2276     if(h_cellmap)
2277         khc_close_space(h_cellmap);
2278     if(h_idc)
2279         khc_close_space(h_idc);
2280     if(h_afs)
2281         khc_close_space(h_afs);
2282     if(h_acells)
2283         khc_close_space(h_acells);
2284     if(id_cell)
2285         PFREE(id_cell);
2286     if(lru_cell)
2287         PFREE(lru_cell);
2288     if(lru_realm)
2289         PFREE(lru_realm);
2290 }
2291
2292 khm_int32
2293 afs_msg_newcred(khm_int32 msg_subtype, 
2294                 khm_ui_4 uparam, 
2295                 void * vparam) {
2296
2297     switch(msg_subtype) {
2298     case KMSG_CRED_NEW_CREDS:
2299         {
2300             khui_new_creds * nc;
2301             khui_new_creds_by_type * nct;
2302             wchar_t wbuf[256];
2303             size_t cbsize;
2304
2305             nc = (khui_new_creds *) vparam;
2306
2307             nct = PMALLOC(sizeof(*nct));
2308             ZeroMemory(nct, sizeof(*nct));
2309
2310             nct->type = afs_credtype_id;
2311             nct->ordinal = 3;
2312
2313             LoadString(hResModule, IDS_AFS_NAME, wbuf, ARRAYLENGTH(wbuf));
2314             StringCbLength(wbuf, sizeof(wbuf), &cbsize);
2315             cbsize += sizeof(wchar_t);
2316
2317             nct->name = PMALLOC(cbsize);
2318             StringCbCopy(nct->name, cbsize, wbuf);
2319
2320             nct->h_module = hResModule;
2321             nct->dlg_proc = afs_dlg_proc;
2322             nct->dlg_template = MAKEINTRESOURCE(IDD_NC_AFS);
2323             nct->type_deps[nct->n_type_deps++] = krb5_credtype_id;
2324
2325             if (krb4_credtype_id < 0) {
2326                 kcdb_credtype_get_id(KRB4_CREDTYPE_NAME,
2327                                      &krb4_credtype_id);
2328             }
2329             if (krb4_credtype_id >= 0) {
2330                 nct->type_deps[nct->n_type_deps++] =
2331                     krb4_credtype_id;
2332             }
2333
2334             khui_cw_add_type(nc, nct);
2335         }
2336         break;
2337
2338     case KMSG_CRED_RENEW_CREDS:
2339         {
2340             khui_new_creds * nc;
2341             khui_new_creds_by_type * nct;
2342
2343             nc = (khui_new_creds *) vparam;
2344
2345             nct = PMALLOC(sizeof(*nct));
2346             ZeroMemory(nct, sizeof(*nct));
2347
2348             nct->type = afs_credtype_id;
2349             nct->type_deps[nct->n_type_deps++] = krb5_credtype_id;
2350             if (krb4_credtype_id < 0) {
2351                 kcdb_credtype_get_id(KRB4_CREDTYPE_NAME,
2352                                      &krb4_credtype_id);
2353             }
2354             if (krb4_credtype_id >= 0) {
2355                 nct->type_deps[nct->n_type_deps++] =
2356                     krb4_credtype_id;
2357             }
2358
2359             khui_cw_add_type(nc, nct);
2360         }
2361         break;
2362
2363     case KMSG_CRED_DIALOG_PRESTART:
2364         {
2365             khui_new_creds * nc;
2366             khui_new_creds_by_type * nct = NULL;
2367             HWND hwnd;
2368
2369             nc = (khui_new_creds *) vparam;
2370             khui_cw_find_type(nc, afs_credtype_id, &nct);
2371
2372             if(!nct)
2373                 break;
2374
2375             hwnd = nct->hwnd_panel;
2376             if (!hwnd)
2377                 break;
2378
2379             PostMessage(hwnd, KHUI_WM_NC_NOTIFY,
2380                         MAKEWPARAM(0,WMNC_DIALOG_SETUP), 0);
2381         }
2382         break;
2383
2384     case KMSG_CRED_DIALOG_NEW_IDENTITY:
2385         {
2386             khui_new_creds * nc;
2387             khui_new_creds_by_type * nct = NULL;
2388             afs_dlg_data * d;
2389
2390             nc = (khui_new_creds *) vparam;
2391             khui_cw_find_type(nc, afs_credtype_id, &nct);
2392
2393             if(nct == NULL)
2394                 break;
2395
2396             d = (afs_dlg_data *) nct->aux;
2397
2398             if(d == NULL)
2399                 break;
2400
2401             EnterCriticalSection(&d->cs);
2402
2403             if (nct->aux == 0) {
2404                 LeaveCriticalSection(&d->cs);
2405                 break;
2406             }
2407
2408             /* we should load up the selected tokens for this
2409                identity */
2410             if(nc->n_identities == 0) {
2411                 LeaveCriticalSection(&d->cs);
2412                 /* no identities selected. nothing to do */
2413                 break;
2414             }
2415
2416             afs_cred_get_identity_creds(&d->creds, nc->identities[0],
2417                                         &d->afs_enabled);
2418
2419             LeaveCriticalSection(&d->cs);
2420
2421             PostMessage(nct->hwnd_panel, KHUI_WM_NC_NOTIFY,
2422                         MAKEWPARAM(0, WMNC_AFS_UPDATE_ROWS), 0);
2423         }
2424         break;
2425
2426     case KMSG_CRED_PROCESS:
2427         {
2428             khui_new_creds * nc;
2429             khui_new_creds_by_type * nct = NULL;
2430             afs_cred_list tlist;
2431             afs_cred_list * l;
2432             int i;
2433             BOOL failed = FALSE;    /* one or more cells failed */
2434             BOOL succeeded = FALSE; /* one or more cells succeeded */
2435             BOOL free_tlist = FALSE;
2436             khm_handle ident = NULL;
2437             afs_dlg_data * d = NULL;
2438             BOOL get_tokens = TRUE;
2439             BOOL ident_renew_triggered = TRUE;
2440             khm_handle csp_afscred = NULL;
2441             khm_handle csp_cells = NULL;
2442
2443             nc = (khui_new_creds *) vparam;
2444             khui_cw_find_type(nc, afs_credtype_id, &nct);
2445
2446             if(!nct)
2447                 break;
2448
2449             _begin_task(0);
2450             _report_cs0(KHERR_INFO,
2451                         L"Getting AFS tokens...");
2452             _describe();
2453
2454             if(nc->result != KHUI_NC_RESULT_PROCESS &&
2455                nc->subtype != KMSG_CRED_RENEW_CREDS) {
2456                 /* nothing to do */
2457                 khui_cw_set_response(nc, afs_credtype_id,
2458                                      KHUI_NC_RESPONSE_SUCCESS);
2459
2460                 _report_cs0(KHERR_INFO, 
2461                             L"Cancelling");
2462                 _end_task();
2463                 break;
2464             }
2465
2466             /* we can't proceed if Kerberos 5 has failed */
2467             if(!khui_cw_type_succeeded(nc, krb5_credtype_id)) {
2468                 khui_cw_set_response(nc, afs_credtype_id,
2469                                      KHUI_NC_RESPONSE_FAILED);
2470
2471                 _report_cs0(KHERR_INFO,
2472                             L"Kerberos 5 plugin failed to process credentials request.  Aborting");
2473                 _end_task();
2474                 break;
2475             }
2476
2477             if (nc->subtype == KMSG_CRED_RENEW_CREDS) {
2478
2479                 if (nc->ctx.scope == KHUI_SCOPE_IDENT ||
2480
2481                     (nc->ctx.scope == KHUI_SCOPE_CREDTYPE &&
2482                      nc->ctx.cred_type == afs_credtype_id) ||
2483
2484                     (nc->ctx.scope == KHUI_SCOPE_CRED &&
2485                      nc->ctx.cred_type == afs_credtype_id)) {
2486
2487                     _report_cs1(KHERR_INFO,
2488                                 L"AFS Renew Creds :: ident %1!p!", 
2489                                 _cptr(nc->ctx.identity));
2490
2491                 } else {
2492
2493                     _report_cs0(KHERR_INFO,
2494                                 L"Renew request not applicable to AFS");
2495                     _end_task();
2496                     break;
2497
2498                 }
2499
2500                 if (nc->ctx.identity != NULL) {
2501                     ident = nc->ctx.identity;
2502                 } else {
2503                     khui_cw_set_response(nc, afs_credtype_id,
2504                                          KHUI_NC_RESPONSE_FAILED);
2505
2506                     _report_cs0(KHERR_INFO,
2507                                 L"No identity specified.  Aborting");
2508                     _end_task();
2509                     break;
2510                 }
2511
2512                 ZeroMemory(&tlist, sizeof(tlist));
2513                 l = &tlist;
2514                 free_tlist = TRUE;
2515
2516                 afs_cred_get_identity_creds(l, ident, NULL);
2517
2518                 /* if the identity has any tokens associated with it
2519                    that aren't persistent, we should renew those as
2520                    well. */
2521                 afs_cred_get_context_creds(l, &nc->ctx);
2522
2523                 if (nc->ctx.scope == KHUI_SCOPE_CREDTYPE ||
2524                     nc->ctx.scope == KHUI_SCOPE_CRED) {
2525
2526                     ident_renew_triggered = FALSE;
2527
2528                 }
2529
2530             } else {
2531                 _report_cs1(KHERR_INFO,
2532                             L"AFS New Creds :: ident %1!p!",
2533                             _cptr(nc->identities[0]));
2534
2535                 d = (afs_dlg_data *) nct->aux;
2536                 if(!d) {
2537                     _report_cs0(KHERR_INFO,
2538                                 L"No dialog data found.  Aborting");
2539
2540                     khui_cw_set_response(nc, afs_credtype_id,
2541                                          KHUI_NC_RESPONSE_FAILED);
2542                     _end_task();
2543                     break;
2544                 }
2545
2546                 EnterCriticalSection(&d->cs);
2547
2548                 l = &d->creds;
2549
2550                 ident = nc->identities[0];
2551                 if (!ident) {
2552                     LeaveCriticalSection(&d->cs);
2553
2554                     _report_cs0(KHERR_INFO,
2555                                 L"No identity specified. Aborting");
2556
2557                     khui_cw_set_response(nc, afs_credtype_id,
2558                                          KHUI_NC_RESPONSE_FAILED);
2559
2560                     _end_task();
2561                     break;
2562                 }
2563
2564                 get_tokens = d->afs_enabled;
2565             }
2566
2567             if (!get_tokens)
2568                 goto _skip_tokens;
2569
2570             if (KHM_SUCCEEDED(kmm_get_plugin_config(AFS_PLUGIN_NAME, 0,
2571                                                     &csp_afscred)))
2572                 khc_open_space(csp_afscred, L"Cells", 0, &csp_cells);
2573
2574             /* looks like k5 worked.  Now see about getting those
2575                tokens */
2576             for(i=0; i<l->n_rows; i++) {
2577                 int code;
2578                 char cell[MAXCELLCHARS];
2579                 char realm[MAXCELLCHARS];
2580                 khm_handle ctoken;
2581                 FILETIME ft_old;
2582                 FILETIME ft_new;
2583                 time_t new_exp = 0;
2584                 khm_size cb;
2585                 khm_int32 method = AFS_TOKEN_AUTO;
2586                 khm_handle csp_cell = NULL;
2587
2588                 if (l->rows[i].flags &
2589                     (DLGROW_FLAG_DONE | DLGROW_FLAG_DELETED))
2590
2591                     continue;
2592
2593                 ZeroMemory(cell, sizeof(cell));
2594                 ZeroMemory(realm, sizeof(realm));
2595
2596                 UnicodeStrToAnsi(cell, sizeof(cell), l->rows[i].cell);
2597                 if (l->rows[i].realm != NULL)
2598                     UnicodeStrToAnsi(realm, sizeof(realm), 
2599                                      l->rows[i].realm);
2600
2601                 ZeroMemory(&ft_old, sizeof(ft_old));
2602
2603                 if (!ident_renew_triggered &&
2604                     (ctoken = afs_find_token(NULL, l->rows[i].cell))) {
2605
2606                     cb = sizeof(ft_old);
2607                     kcdb_cred_get_attr(ctoken, KCDB_ATTR_EXPIRE,
2608                                        NULL, &ft_old, &cb);
2609
2610                     kcdb_cred_release(ctoken);
2611                 }
2612
2613                 if (l->rows[i].method == AFS_TOKEN_AUTO && csp_cells &&
2614                     KHM_SUCCEEDED(khc_open_space(csp_cells,
2615                                                  l->rows[i].cell, 0,
2616                                                  &csp_cell))) {
2617
2618                     if (KHM_FAILED(khc_read_int32(csp_cell, L"Method", &method))) {
2619                         method = l->rows[i].method;
2620                     } else {
2621                         _report_cs3(KHERR_INFO,
2622                                     L"Overriding method %1!d! with global default %2!d! for cell %3!s!",
2623                                     _int32(l->rows[i].method),
2624                                     _int32(method),
2625                                     _cstr(l->rows[i].cell));
2626                         _resolve();
2627                     }
2628
2629                     khc_close_space(csp_cell);               
2630                 } else {
2631                     method = l->rows[i].method;
2632                 }
2633
2634                 _report_cs3(KHERR_INFO,
2635                             L"Getting tokens for cell %1!S! with realm %2!S! using method %3!d!",
2636                             _cstr(cell),
2637                             _cstr(realm),
2638                             _int32(method));
2639                 _resolve();
2640
2641                 /* make the call */
2642                 code = afs_klog(ident, "", cell, realm, 0, 
2643                                 method, &new_exp);
2644
2645                 _report_cs1(KHERR_INFO,
2646                             L"klog returns code %1!d!",
2647                             _int32(code));
2648
2649                 if(code) {
2650                     failed = TRUE;
2651                     l->rows[i].flags &= ~DLGROW_FLAG_DONE;
2652
2653                     if (!kherr_is_error()) {
2654                         /* failed to get tokens, but no error was reported */
2655                         _report_sr1(KHERR_ERROR, IDS_ERR_GENERAL,
2656                                     _cptr(cell));
2657                         _resolve();
2658                     }
2659
2660                 } else {
2661                     l->rows[i].flags |= DLGROW_FLAG_DONE;
2662                     succeeded = TRUE;
2663
2664                     if (new_exp &&
2665                         !ident_renew_triggered) {
2666                         TimetToFileTime(new_exp, &ft_new);
2667
2668                         if (CompareFileTime(&ft_old, &ft_new) >= 0) {
2669                             /* getting a new token didn't improve the
2670                                situation much.  We only get here if we
2671                                were trying to renew tokens. So we try
2672                                to trigger an identity renewal.  Doing
2673                                so should get us new initial tickets
2674                                which will allow us to get a better
2675                                token. */
2676
2677                             khui_action_context ctx;
2678
2679                             _reportf(L"Renewal of AFS tokens for cell %s failed to get a longer token.  Triggering identity renewal", l->rows[i].cell);
2680
2681                             khui_context_create(&ctx,
2682                                                 KHUI_SCOPE_IDENT,
2683                                                 nc->ctx.identity,
2684                                                 KCDB_CREDTYPE_INVALID,
2685                                                 NULL);
2686                             khui_action_trigger(KHUI_ACTION_RENEW_CRED,
2687                                                 &ctx);
2688
2689                             khui_context_release(&ctx);
2690
2691                             ident_renew_triggered = TRUE;
2692                         }
2693                     }
2694                 }
2695             }
2696
2697         _skip_tokens:
2698
2699             if(failed) {
2700                 /* we should indicate errors if anything went wrong */
2701                 khui_cw_set_response(nc, afs_credtype_id, 
2702                                      KHUI_NC_RESPONSE_FAILED);
2703             } else {
2704                 khui_cw_set_response(nc, afs_credtype_id,
2705                                      KHUI_NC_RESPONSE_SUCCESS);
2706             }
2707
2708             if (succeeded && nc->subtype == KMSG_CRED_RENEW_CREDS) {
2709                 afs_ident_token_set b;
2710
2711                 afs_list_tokens_internal();
2712
2713                 /* the tokens that we just acquired need adjusting to
2714                    include the realm, method and identity information
2715                    derived from the new creds operation.  this is done
2716                    in afs_adjust_token_ident_proc */
2717                 b.ident = ident;
2718                 b.l = l;
2719                 b.add_new = FALSE;
2720                 b.update_info = FALSE;
2721
2722                 kcdb_credset_apply(afs_credset, afs_adjust_token_ident_proc, 
2723                                    (void *) &b);
2724
2725                 kcdb_credset_collect(NULL, afs_credset, NULL, 
2726                                      afs_credtype_id, NULL);
2727
2728             } else if (nc->subtype == KMSG_CRED_NEW_CREDS) {
2729                 afs_ident_token_set b;
2730
2731                 afs_list_tokens_internal();
2732
2733                 /* the tokens that we just acquired need adjusting to
2734                    include the realm, method and identity information
2735                    derived from the new creds operation.  this is done
2736                    in afs_adjust_token_ident_proc */
2737                 b.ident = ident;
2738                 b.l = l;
2739                 b.add_new = FALSE;
2740                 b.update_info = FALSE;
2741
2742                 kcdb_credset_apply(afs_credset, afs_adjust_token_ident_proc, 
2743                                    (void *) &b);
2744
2745                 kcdb_credset_collect(NULL, afs_credset, NULL, 
2746                                      afs_credtype_id, NULL);
2747
2748                 afs_cred_write_ident_data(d);
2749             }
2750
2751             if (d)
2752                 LeaveCriticalSection(&d->cs);
2753
2754             if (free_tlist) {
2755                 afs_cred_free_rows(&tlist);
2756             }
2757
2758             if (csp_afscred)
2759                 khc_close_space(csp_afscred);
2760
2761             if (csp_cells)
2762                 khc_close_space(csp_cells);
2763
2764             _end_task();
2765         }
2766         break;
2767
2768     case KMSG_CRED_END:
2769         {
2770             khui_new_creds * nc;
2771             khui_new_creds_by_type * nct;
2772
2773             nc = (khui_new_creds *) vparam;
2774             khui_cw_find_type(nc, afs_credtype_id, &nct);
2775
2776             if(!nct)
2777                 break;
2778
2779             khui_cw_del_type(nc, afs_credtype_id);
2780     
2781             if (nct->name)
2782                 PFREE(nct->name);
2783             if (nct->credtext)
2784                 PFREE(nct->credtext);
2785
2786             PFREE(nct);
2787         }
2788         break;
2789     }
2790
2791     return KHM_ERROR_SUCCESS;
2792 }