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