windows-nim-afs-20070617
[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                                                -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                                            -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, -1, 
1738                                                       (LPARAM) s) == CB_ERR) {
1739                                     idx = 
1740                                         (int)
1741                                         SendDlgItemMessage(hwnd, 
1742                                                            IDC_NCAFS_REALM, 
1743                                                            CB_ADDSTRING, 
1744                                                            0, (LPARAM) s);
1745                                     SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, 
1746                                                        CB_SETITEMDATA, 
1747                                                        idx, FALSE);
1748                                 }
1749
1750                                 s += wcslen(s) + 1;
1751                             }
1752                             PFREE(buf);
1753                         }
1754                     }
1755
1756                     if (d->nc)
1757                         khui_cw_enable_type(d->nc, afs_credtype_id, 
1758                                             d->afs_enabled);
1759
1760                     nc_dlg_enable(hwnd, d->afs_enabled);
1761
1762                     afs_dlg_update_rows(hwnd, d);
1763                 }
1764                 break;
1765
1766             case WMNC_UPDATE_CREDTEXT:
1767                 {
1768                     wchar_t wformat[256];
1769                     wchar_t wstr[2048];
1770                     khm_int32 flags;
1771
1772                     if(nct->credtext) {
1773                         PFREE(nct->credtext);
1774                         nct->credtext = NULL;
1775                     }
1776
1777 #ifdef DEBUG
1778                     assert(d->nc);
1779 #endif
1780
1781                     if (d->nc->n_identities == 0 ||
1782                         KHM_FAILED(kcdb_identity_get_flags(d->nc->identities[0],
1783                                                            &flags)) ||
1784                         !(flags & KCDB_IDENT_FLAG_VALID))
1785                         /* in this case, we don't show any credential text */
1786                         break;
1787
1788                     wstr[0] = 0;
1789
1790                     if(!d->afs_enabled) {
1791                         LoadString(hResModule, IDS_AFS_CREDTEXT_DIS, 
1792                                    wstr, ARRAYLENGTH(wstr));
1793                     } else {
1794                         if(d->creds.n_rows == 0) {
1795                             LoadString(hResModule, IDS_AFS_CREDTEXT_0, 
1796                                        wstr, ARRAYLENGTH(wstr));
1797                         } else if(d->creds.n_rows == 1) {
1798                             LoadString(hResModule, IDS_AFS_CREDTEXT_1, 
1799                                        wformat, ARRAYLENGTH(wformat));
1800                             StringCbPrintf(wstr, sizeof(wstr), wformat, 
1801                                            d->creds.rows[0].cell);
1802                         } else {
1803                             int i;
1804                             wchar_t wcells[1024];
1805
1806                             LoadString(hResModule, IDS_AFS_CREDTEXT_N, 
1807                                        wformat, ARRAYLENGTH(wformat));
1808                             wcells[0] = 0;
1809                             for(i=0; i<d->creds.n_rows; i++) {
1810                                 if(i > 0)
1811                                     StringCbCat(wcells, sizeof(wcells), 
1812                                                 L", ");
1813                                 if(FAILED(StringCbCat(wcells, 
1814                                                       sizeof(wcells), 
1815                                                       d->creds.rows[i].cell))) {
1816                                     size_t cch;
1817                                     /* looks like we overflowed */
1818                                     /* add an ellipsis at the end */
1819                                     StringCchLength(wcells, ARRAYLENGTH(wcells), &cch);
1820                                     cch = min(ARRAYLENGTH(wcells) - 4, cch);
1821                                     StringCchCopy(wcells + cch, 4, L"...");
1822
1823                                     break;
1824                                 }
1825                             }
1826
1827                             StringCbPrintf(wstr, sizeof(wstr), wformat, wcells);
1828                         }
1829                     }
1830
1831                     if(wstr[0] != 0) {
1832                         size_t cbs;
1833                         StringCbLength(wstr, sizeof(wstr), &cbs);
1834                         cbs += sizeof(wchar_t);
1835                         assert(nct->credtext == NULL);
1836                         nct->credtext = PMALLOC(cbs);
1837                         StringCbCopy(nct->credtext, cbs, wstr);
1838                     } else {
1839                         /* something went wrong */
1840                         nct->credtext = NULL;
1841                     }
1842                 }
1843                 break;
1844
1845             case WMNC_CREDTEXT_LINK:
1846                 {
1847                     khui_htwnd_link * l;
1848                     wchar_t wid[KHUI_MAXCCH_HTLINK_FIELD];
1849                     wchar_t * wids;
1850
1851                     l = (khui_htwnd_link *) lParam;
1852
1853                     StringCchCopyN(wid, ARRAYLENGTH(wid), l->id, l->id_len);
1854                     wids = wcschr(wid, L':');
1855                         
1856                     if(!wids)
1857                         break;
1858                     else
1859                         wids++;
1860
1861 #ifdef DEBUG
1862                     assert(d->nc);
1863 #endif
1864
1865                     if(!wcscmp(wids, L"Enable")) {
1866                         SendDlgItemMessage(hwnd, IDC_NCAFS_OBTAIN, 
1867                                            BM_SETCHECK, BST_CHECKED, 0);
1868                         d->afs_enabled = TRUE;
1869                         khui_cw_enable_type(d->nc, afs_credtype_id, TRUE);
1870                         nc_dlg_enable(hwnd, TRUE);
1871                     }
1872                 }
1873                 break;
1874
1875             case WMNC_IDENTITY_CHANGE:
1876                 kmq_post_sub_msg(afs_sub, KMSG_CRED, 
1877                                  KMSG_CRED_DIALOG_NEW_IDENTITY, 0, 
1878                                  (void *) d->nc);
1879                 break;
1880                 
1881             case WMNC_AFS_UPDATE_ROWS:
1882                 afs_dlg_update_rows(hwnd, d);
1883
1884 #ifdef DEBUG
1885                 assert(d->nc);
1886 #endif
1887
1888                 PostMessage(d->nc->hwnd, KHUI_WM_NC_NOTIFY, 
1889                             MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), 0);
1890                 break;
1891             }
1892
1893             LeaveCriticalSection(&d->cs);
1894         }
1895         return TRUE;
1896
1897     case WM_NOTIFY:
1898         if(wParam == IDC_NCAFS_TOKENLIST) {
1899             LPNMHDR lpnmh = (LPNMHDR) lParam;
1900
1901             if(lpnmh->code == LVN_ITEMCHANGED) {
1902                 /* when an item in the list view is clicked, we
1903                    load the corresponding values into the edit and
1904                    combo boxes */
1905                 NMLISTVIEW *lpnmlv = (NMLISTVIEW *) lpnmh;
1906                 LVITEM lvi;
1907                 HWND hw;
1908                 int idx;
1909                 int row;
1910                 afs_dlg_data * d;
1911
1912                 if (!(lpnmlv->uChanged & LVIF_STATE) ||
1913                     !(lpnmlv->uNewState & LVIS_SELECTED) ||
1914                     (lpnmlv->iItem == -1))
1915
1916                     return TRUE;
1917
1918                 d = (afs_dlg_data *)(LONG_PTR) 
1919                     GetWindowLongPtr(hwnd, DWLP_USER);
1920
1921                 if (d == NULL)
1922                     return FALSE;
1923
1924                 EnterCriticalSection(&d->cs);
1925
1926                 hw = GetDlgItem(hwnd, IDC_NCAFS_TOKENLIST);
1927
1928                 idx = lpnmlv->iItem;
1929
1930                 ZeroMemory(&lvi, sizeof(lvi));
1931                 lvi.iItem = idx;
1932                 lvi.iSubItem = 0;
1933                 lvi.mask = LVIF_PARAM;
1934
1935                 if(!ListView_GetItem(hw, &lvi))
1936                     goto _done_notify_select;
1937
1938                 /* ok, now lvi.lParam should be the row of the token */
1939                 row = (int) lvi.lParam;
1940                 if(row < 0 || row >= d->creds.n_rows)
1941                     goto _done_notify_select;
1942
1943                 SetDlgItemText(hwnd, IDC_NCAFS_CELL, 
1944                                d->creds.rows[row].cell);
1945                 if(d->creds.rows[row].realm != NULL) {
1946                     SetDlgItemText(hwnd, IDC_NCAFS_REALM, 
1947                                    d->creds.rows[row].realm);
1948                 } else {
1949                     wchar_t wbuf[256];
1950                     int idx;
1951                         
1952                     LoadString(hResModule, IDS_NC_REALM_AUTO, wbuf, 
1953                                ARRAYLENGTH(wbuf));
1954                     idx = (int) SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, 
1955                                                    CB_FINDSTRINGEXACT, -1, 
1956                                                    (LPARAM) wbuf);
1957                     SendDlgItemMessage(hwnd, IDC_NCAFS_REALM, CB_SETCURSEL,
1958                                        idx, 0);
1959                 }
1960                 SendDlgItemMessage(hwnd, IDC_NCAFS_METHOD, CB_SETCURSEL, 
1961                                    d->creds.rows[row].method, 0);
1962             _done_notify_select:
1963                 LeaveCriticalSection(&d->cs);
1964
1965             } else if (lpnmh->code == NM_DBLCLK) {
1966
1967                 LPNMITEMACTIVATE pnmi;
1968                 LVITEM lvi;
1969                 HWND hw;
1970                 afs_dlg_data * d;
1971                 int row;
1972                 int x,y;
1973                 RECT r;
1974
1975                 d = (afs_dlg_data *)(LONG_PTR) 
1976                     GetWindowLongPtr(hwnd, DWLP_USER);
1977
1978                 if (d == NULL)
1979                     return FALSE;
1980
1981                 EnterCriticalSection(&d->cs);
1982
1983                 pnmi = (LPNMITEMACTIVATE) lpnmh;
1984
1985                 hw = GetDlgItem(hwnd, IDC_NCAFS_TOKENLIST);
1986
1987                 ZeroMemory(&lvi, sizeof(lvi));
1988                 lvi.iItem = pnmi->iItem;
1989                 lvi.iSubItem = 0;
1990                 lvi.mask = LVIF_PARAM;
1991
1992                 if (!ListView_GetItem(hw, &lvi))
1993                     goto _done_notify_click;
1994
1995                 row = (int) lvi.lParam;
1996                 if(row < 0 || row >= d->creds.n_rows)
1997                     goto _done_notify_click;
1998
1999                 ListView_GetItemRect(hw, pnmi->iItem, &r, LVIR_SELECTBOUNDS);
2000                 x = (r.left + r.right) / 2;
2001                 y = (r.bottom);
2002
2003                 GetWindowRect(hw, &r);
2004                 y += r.top;
2005                 x += r.left;
2006
2007                 if (d->creds.rows[row].flags & DLGROW_FLAG_NOTOWNED) {
2008                     nc_dlg_show_tooltip(hwnd, 0,
2009                                         MAKEINTRESOURCE(IDS_NC_TT_CONFLICTD),
2010                                         MAKEINTRESOURCE(IDS_NC_TT_PROBLEM),
2011                                         2,
2012                                         x,y);
2013                 } else if (d->creds.rows[row].flags &
2014                            DLGROW_FLAG_EXPIRED) {
2015                     nc_dlg_show_tooltip(hwnd, 0,
2016                                         MAKEINTRESOURCE(IDS_NC_TT_EXPIRED),
2017                                         MAKEINTRESOURCE(IDS_NC_TT_DETAILS),
2018                                         1,
2019                                         x, y);
2020                 } else if (d->creds.rows[row].flags &
2021                            DLGROW_FLAG_EXISTS) {
2022                     nc_dlg_show_tooltip(hwnd, 0,
2023                                         MAKEINTRESOURCE(IDS_NC_TT_EXISTS),
2024                                         MAKEINTRESOURCE(IDS_NC_TT_DETAILS),
2025                                         1, x, y);
2026                 } else {
2027                     nc_dlg_show_tooltip(hwnd, 0,
2028                                         MAKEINTRESOURCE(IDS_NC_TT_NEW),
2029                                         MAKEINTRESOURCE(IDS_NC_TT_DETAILS),
2030                                         1, x, y);
2031                 }
2032
2033             _done_notify_click:
2034                 LeaveCriticalSection(&d->cs);
2035             }
2036         }
2037         return TRUE;
2038
2039     case WM_TIMER:
2040         {
2041             if(wParam == DLG_TOOLTIP_TIMER_ID) {
2042                 KillTimer(hwnd, DLG_TOOLTIP_TIMER_ID);
2043                 nc_dlg_hide_tooltip(hwnd, 0);
2044             }
2045         }
2046         return TRUE;
2047
2048     case WM_HELP:
2049         {
2050             static const DWORD ctx_help[] = {
2051                 IDC_NCAFS_OBTAIN, IDH_OBTAIN,
2052                 IDC_NCAFS_CELL, IDH_CELL,
2053                 IDC_NCAFS_REALM, IDH_REALM,
2054                 IDC_NCAFS_METHOD, IDH_METHOD,
2055                 IDC_NCAFS_ADD_TOKEN, IDH_ADD,
2056                 IDC_NCAFS_DELETE_TOKEN, IDH_DELETE,
2057                 IDC_NCAFS_TOKENLIST, IDH_TOKENLIST,
2058                 0
2059             };
2060
2061             LPHELPINFO hlp;
2062
2063             hlp = (LPHELPINFO) lParam;
2064
2065             if (hlp->iContextType != HELPINFO_WINDOW)
2066                 break;
2067
2068             afs_html_help(hlp->hItemHandle, L"::/popups_newcred.txt",
2069                           HH_TP_HELP_WM_HELP, (DWORD_PTR) ctx_help);
2070         }
2071         return TRUE;
2072     } /* switch(uMsg) */
2073
2074     return FALSE;
2075 }
2076
2077
2078 /* passed in to kcdb_credset_apply along with the afs_credset to adjust
2079    newly acquired credentials to include informatino derived from the
2080    new creds operation */
2081 khm_int32 KHMAPI 
2082 afs_adjust_token_ident_proc(khm_handle cred, void * vd)
2083 {
2084     wchar_t cell[MAXCELLCHARS];
2085     afs_ident_token_set * b = (afs_ident_token_set *) vd;
2086     afs_cred_list * l;
2087     khm_size cbbuf;
2088     int i;
2089
2090     l = b->l;
2091
2092     /* ASSUMPTION: for each user, there can be tokens for only one
2093        cell */
2094
2095     cbbuf = sizeof(cell);
2096
2097     if(KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_cell, NULL, cell, &cbbuf)))
2098         return KHM_ERROR_SUCCESS; /* remember, kcdb doesn't care if
2099                                      this run succeeded or not.  all
2100                                      it wants to know if whether or
2101                                      not we want to continue the
2102                                      search */
2103     
2104     for(i=0; i<l->n_rows; i++) {
2105         if((l->rows[i].flags & DLGROW_FLAG_DONE) && 
2106            !_wcsicmp(cell, l->rows[i].cell)) {
2107             khm_int32 method;
2108
2109             kcdb_cred_set_identity(cred, b->ident);
2110             if(l->rows[i].realm)
2111                 kcdb_cred_set_attr(cred, afs_attr_realm, l->rows[i].realm, 
2112                                    KCDB_CBSIZE_AUTO);
2113             else
2114                 kcdb_cred_set_attr(cred, afs_attr_realm, NULL, 0);
2115
2116             method = l->rows[i].method;
2117             kcdb_cred_set_attr(cred, afs_attr_method, &method, 
2118                                KCDB_CBSIZE_AUTO);
2119
2120             break;
2121         }
2122     }
2123
2124     return KHM_ERROR_SUCCESS;
2125 }
2126
2127 void
2128 afs_cred_write_ident_data(afs_dlg_data * d) {
2129     wchar_t * lru_cell = NULL;
2130     wchar_t * lru_realm = NULL;
2131     wchar_t * id_cell = NULL;
2132     khm_size cbidcell;
2133     khm_size cbcell;
2134     khm_size cbrealm;
2135     khm_size cbt;
2136     size_t cbz;
2137     khm_handle h_idc = NULL;
2138     khm_handle h_afs = NULL;
2139     khm_handle h_acells = NULL;
2140     khm_handle h_cellmap = NULL;
2141     wchar_t idname[KCDB_IDENT_MAXCCH_NAME];
2142     khm_handle ident = NULL;
2143     afs_cred_list * l;
2144     int i;
2145
2146     l = &d->creds;
2147
2148     if (d->nc &&
2149         d->nc->n_identities > 0 &&
2150         d->nc->identities[0])
2151
2152         ident = d->nc->identities[0];
2153
2154     else if (d->config_dlg)
2155
2156         ident = d->ident;
2157
2158     if (!ident)
2159         return;
2160
2161     cbt = sizeof(idname);
2162     kcdb_identity_get_name(ident, idname, &cbt);
2163
2164     khc_open_space(csp_afscred, L"Cells", 0, &h_cellmap);
2165
2166     if(ident) {
2167         if(KHM_SUCCEEDED(kcdb_identity_get_config(ident,
2168                                                   KHM_FLAG_CREATE,
2169                                                   &h_idc))) {
2170             khc_open_space(h_idc, CSNAME_AFSCRED, 
2171                            KHM_FLAG_CREATE, &h_afs);
2172         }
2173
2174         if(h_afs) {
2175             khc_open_space(h_afs, L"Cells", KHM_FLAG_CREATE, 
2176                            &h_acells);
2177         }
2178     }
2179
2180     if (h_afs && d) {
2181         khc_write_int32(h_afs, L"AFSEnabled",
2182                         !!d->afs_enabled);
2183     }
2184
2185     if(khc_read_multi_string(csp_params, 
2186                              L"LRUCells", 
2187                              NULL,
2188                              &cbcell) == KHM_ERROR_TOO_LONG) {
2189         cbcell += MAXCELLCHARS * sizeof(wchar_t) * 
2190             l->n_rows;
2191         lru_cell = PMALLOC(cbcell);
2192         ZeroMemory(lru_cell, cbcell);
2193         cbt = cbcell;
2194                     
2195         khc_read_multi_string(csp_params,
2196                               L"LRUCells",
2197                               lru_cell,
2198                               &cbt);
2199     } else {
2200         cbcell = MAXCELLCHARS * sizeof(wchar_t) * l->n_rows + sizeof(wchar_t);
2201         if (l->n_rows > 0) {
2202             lru_cell = PMALLOC(cbcell);
2203             ZeroMemory(lru_cell, cbcell);
2204         } else {
2205             lru_cell = NULL;
2206             cbcell = 0;
2207         }
2208     }
2209
2210     if(khc_read_multi_string(csp_params,
2211                              L"LRURealms",
2212                              NULL,
2213                              &cbrealm) == KHM_ERROR_TOO_LONG) {
2214         cbrealm += MAXCELLCHARS * sizeof(wchar_t) * l->n_rows;
2215         lru_realm = PMALLOC(cbrealm);
2216         ZeroMemory(lru_realm, cbrealm);
2217         cbt = cbrealm;
2218
2219         khc_read_multi_string(csp_params,
2220                               L"LRURealms",
2221                               lru_realm,
2222                               &cbt);
2223     } else {
2224         cbrealm = MAXCELLCHARS * sizeof(wchar_t) * l->n_rows + sizeof(wchar_t);
2225         if (l->n_rows > 0) {
2226             lru_realm = PMALLOC(cbrealm);
2227             ZeroMemory(lru_realm, cbrealm);
2228         } else {
2229             lru_cell = NULL;
2230             cbrealm = 0;
2231         }
2232     }
2233
2234     cbidcell = MAXCELLCHARS * sizeof(wchar_t) * l->n_rows + sizeof(wchar_t);
2235     if (l->n_rows > 0) {
2236         id_cell = PMALLOC(cbidcell);
2237         ZeroMemory(id_cell, cbidcell);
2238     } else {
2239         id_cell = NULL;
2240         cbidcell = 0;
2241     }
2242
2243     for(i=0; i < l->n_rows; i++)
2244         if(!(l->rows[i].flags & DLGROW_FLAG_DELETED)) {
2245             khm_handle h_acell = NULL;
2246             
2247             if(!multi_string_find(lru_cell, 
2248                                   l->rows[i].cell, 0)) {
2249                 cbz = cbcell;
2250                 multi_string_append(lru_cell, &cbz, 
2251                                     l->rows[i].cell);
2252             }
2253
2254             if(l->rows[i].realm && 
2255                !multi_string_find(lru_realm, 
2256                                   l->rows[i].realm, 0)) {
2257                 cbz = cbrealm;
2258                 multi_string_append(lru_realm, &cbz, 
2259                                     l->rows[i].realm);
2260             }
2261
2262             cbz = cbidcell;
2263             multi_string_append(id_cell, &cbz, 
2264                                 l->rows[i].cell);
2265
2266             if(h_acells && 
2267                KHM_SUCCEEDED(khc_open_space(h_acells, 
2268                                             l->rows[i].cell, 
2269                                             KHM_FLAG_CREATE, 
2270                                             &h_acell))) {
2271                 wchar_t methodname[KHUI_MAXCCH_NAME];
2272
2273                 afs_get_method_name(l->rows[i].method,
2274                                     methodname,
2275                                     sizeof(methodname));
2276
2277                 khc_write_string(h_acell, L"MethodName", 
2278                                  methodname);
2279
2280                 if(l->rows[i].realm)
2281                     khc_write_string(h_acell, L"Realm", 
2282                                      l->rows[i].realm);
2283                 else
2284                     khc_write_string(h_acell, L"Realm", L"");
2285                 khc_close_space(h_acell);
2286             }
2287
2288             if (l->rows[i].flags & DLGROW_FLAG_DONE) {
2289                 if (h_cellmap) {
2290                     khc_write_string(h_cellmap,
2291                                      l->rows[i].cell,
2292                                      idname);
2293                 }
2294             }
2295         }
2296
2297     if (lru_cell)                
2298         khc_write_multi_string(csp_params,
2299                                L"LRUCells", lru_cell);
2300     if (lru_realm)
2301         khc_write_multi_string(csp_params,
2302                                L"LRURealms", lru_realm);
2303     if (id_cell)
2304         khc_write_multi_string(h_afs, L"Cells",
2305                                id_cell);
2306     else
2307         khc_write_multi_string(h_afs, L"Cells", L"\0");
2308
2309     if (d->config_dlg) {
2310         if (d->dirty)
2311             khui_cfg_set_flags_inst(&d->cfg, KHUI_CNFLAG_APPLIED,
2312                                     KHUI_CNFLAG_APPLIED |
2313                                     KHUI_CNFLAG_MODIFIED);
2314         else
2315             khui_cfg_set_flags_inst(&d->cfg, 0,
2316                                     KHUI_CNFLAG_MODIFIED);
2317     }
2318
2319     d->dirty = FALSE;
2320
2321     if(h_cellmap)
2322         khc_close_space(h_cellmap);
2323     if(h_idc)
2324         khc_close_space(h_idc);
2325     if(h_afs)
2326         khc_close_space(h_afs);
2327     if(h_acells)
2328         khc_close_space(h_acells);
2329     if(id_cell)
2330         PFREE(id_cell);
2331     if(lru_cell)
2332         PFREE(lru_cell);
2333     if(lru_realm)
2334         PFREE(lru_realm);
2335 }
2336
2337 khm_int32
2338 afs_msg_newcred(khm_int32 msg_subtype, 
2339                 khm_ui_4 uparam, 
2340                 void * vparam) {
2341
2342     switch(msg_subtype) {
2343     case KMSG_CRED_NEW_CREDS:
2344         {
2345             khui_new_creds * nc;
2346             khui_new_creds_by_type * nct;
2347             wchar_t wbuf[256];
2348             size_t cbsize;
2349
2350             nc = (khui_new_creds *) vparam;
2351
2352             nct = PMALLOC(sizeof(*nct));
2353             ZeroMemory(nct, sizeof(*nct));
2354
2355             nct->type = afs_credtype_id;
2356             nct->ordinal = 3;
2357
2358             LoadString(hResModule, IDS_AFS_NAME, wbuf, ARRAYLENGTH(wbuf));
2359             StringCbLength(wbuf, sizeof(wbuf), &cbsize);
2360             cbsize += sizeof(wchar_t);
2361
2362             nct->name = PMALLOC(cbsize);
2363             StringCbCopy(nct->name, cbsize, wbuf);
2364
2365             nct->h_module = hResModule;
2366             nct->dlg_proc = afs_dlg_proc;
2367             nct->dlg_template = MAKEINTRESOURCE(IDD_NC_AFS);
2368             nct->type_deps[nct->n_type_deps++] = krb5_credtype_id;
2369
2370             if (krb4_credtype_id < 0) {
2371                 kcdb_credtype_get_id(KRB4_CREDTYPE_NAME,
2372                                      &krb4_credtype_id);
2373             }
2374             if (krb4_credtype_id >= 0) {
2375                 nct->type_deps[nct->n_type_deps++] =
2376                     krb4_credtype_id;
2377             }
2378
2379             khui_cw_add_type(nc, nct);
2380         }
2381         break;
2382
2383     case KMSG_CRED_RENEW_CREDS:
2384         {
2385             khui_new_creds * nc;
2386             khui_new_creds_by_type * nct;
2387
2388             nc = (khui_new_creds *) vparam;
2389
2390             nct = PMALLOC(sizeof(*nct));
2391             ZeroMemory(nct, sizeof(*nct));
2392
2393             nct->type = afs_credtype_id;
2394             nct->type_deps[nct->n_type_deps++] = krb5_credtype_id;
2395             if (krb4_credtype_id < 0) {
2396                 kcdb_credtype_get_id(KRB4_CREDTYPE_NAME,
2397                                      &krb4_credtype_id);
2398             }
2399             if (krb4_credtype_id >= 0) {
2400                 nct->type_deps[nct->n_type_deps++] =
2401                     krb4_credtype_id;
2402             }
2403
2404             khui_cw_add_type(nc, nct);
2405         }
2406         break;
2407
2408     case KMSG_CRED_DIALOG_PRESTART:
2409         {
2410             khui_new_creds * nc;
2411             khui_new_creds_by_type * nct = NULL;
2412             HWND hwnd;
2413
2414             nc = (khui_new_creds *) vparam;
2415             khui_cw_find_type(nc, afs_credtype_id, &nct);
2416
2417             if(!nct)
2418                 break;
2419
2420             hwnd = nct->hwnd_panel;
2421             if (!hwnd)
2422                 break;
2423
2424             PostMessage(hwnd, KHUI_WM_NC_NOTIFY,
2425                         MAKEWPARAM(0,WMNC_DIALOG_SETUP), 0);
2426         }
2427         break;
2428
2429     case KMSG_CRED_DIALOG_NEW_IDENTITY:
2430         {
2431             khui_new_creds * nc;
2432             khui_new_creds_by_type * nct = NULL;
2433             afs_dlg_data * d;
2434
2435             nc = (khui_new_creds *) vparam;
2436             khui_cw_find_type(nc, afs_credtype_id, &nct);
2437
2438             if(nct == NULL)
2439                 break;
2440
2441             d = (afs_dlg_data *) nct->aux;
2442
2443             if(d == NULL)
2444                 break;
2445
2446             EnterCriticalSection(&d->cs);
2447
2448             if (nct->aux == 0) {
2449                 LeaveCriticalSection(&d->cs);
2450                 break;
2451             }
2452
2453             /* we should load up the selected tokens for this
2454                identity */
2455             if(nc->n_identities == 0) {
2456                 LeaveCriticalSection(&d->cs);
2457                 /* no identities selected. nothing to do */
2458                 break;
2459             }
2460
2461             afs_cred_get_identity_creds(&d->creds, nc->identities[0],
2462                                         &d->afs_enabled);
2463
2464             LeaveCriticalSection(&d->cs);
2465
2466             PostMessage(nct->hwnd_panel, KHUI_WM_NC_NOTIFY,
2467                         MAKEWPARAM(0, WMNC_AFS_UPDATE_ROWS), 0);
2468         }
2469         break;
2470
2471     case KMSG_CRED_PROCESS:
2472         {
2473             khui_new_creds * nc;
2474             khui_new_creds_by_type * nct = NULL;
2475             afs_cred_list tlist;
2476             afs_cred_list * l;
2477             int i;
2478             BOOL failed = FALSE;    /* one or more cells failed */
2479             BOOL succeeded = FALSE; /* one or more cells succeeded */
2480             BOOL free_tlist = FALSE;
2481             khm_handle ident = NULL;
2482             afs_dlg_data * d = NULL;
2483             BOOL get_tokens = TRUE;
2484             BOOL ident_renew_triggered = TRUE;
2485             khm_handle csp_afscred = NULL;
2486             khm_handle csp_cells = NULL;
2487
2488             nc = (khui_new_creds *) vparam;
2489             khui_cw_find_type(nc, afs_credtype_id, &nct);
2490
2491             if(!nct)
2492                 break;
2493
2494             _begin_task(0);
2495             _report_cs0(KHERR_INFO,
2496                         L"Getting AFS tokens...");
2497             _describe();
2498
2499             if(nc->result != KHUI_NC_RESULT_PROCESS &&
2500                nc->subtype != KMSG_CRED_RENEW_CREDS) {
2501                 /* nothing to do */
2502                 khui_cw_set_response(nc, afs_credtype_id,
2503                                      KHUI_NC_RESPONSE_SUCCESS);
2504
2505                 _report_cs0(KHERR_INFO, 
2506                             L"Cancelling");
2507                 _end_task();
2508                 break;
2509             }
2510
2511             /* we can't proceed if Kerberos 5 has failed */
2512             if(!khui_cw_type_succeeded(nc, krb5_credtype_id)) {
2513                 khui_cw_set_response(nc, afs_credtype_id,
2514                                      KHUI_NC_RESPONSE_FAILED);
2515
2516                 _report_cs0(KHERR_INFO,
2517                             L"Kerberos 5 plugin failed to process credentials request.  Aborting");
2518                 _end_task();
2519                 break;
2520             }
2521
2522             if (nc->subtype == KMSG_CRED_RENEW_CREDS) {
2523
2524                 if (nc->ctx.scope == KHUI_SCOPE_IDENT ||
2525
2526                     (nc->ctx.scope == KHUI_SCOPE_CREDTYPE &&
2527                      nc->ctx.cred_type == afs_credtype_id) ||
2528
2529                     (nc->ctx.scope == KHUI_SCOPE_CRED &&
2530                      nc->ctx.cred_type == afs_credtype_id)) {
2531
2532                     _report_cs1(KHERR_INFO,
2533                                 L"AFS Renew Creds :: ident %1!p!", 
2534                                 _cptr(nc->ctx.identity));
2535
2536                 } else {
2537
2538                     _report_cs0(KHERR_INFO,
2539                                 L"Renew request not applicable to AFS");
2540                     _end_task();
2541                     break;
2542
2543                 }
2544
2545                 if (nc->ctx.identity != NULL) {
2546                     ident = nc->ctx.identity;
2547                 } else {
2548                     khui_cw_set_response(nc, afs_credtype_id,
2549                                          KHUI_NC_RESPONSE_FAILED);
2550
2551                     _report_cs0(KHERR_INFO,
2552                                 L"No identity specified.  Aborting");
2553                     _end_task();
2554                     break;
2555                 }
2556
2557                 ZeroMemory(&tlist, sizeof(tlist));
2558                 l = &tlist;
2559                 free_tlist = TRUE;
2560
2561                 afs_cred_get_identity_creds(l, ident, NULL);
2562
2563                 /* if the identity has any tokens associated with it
2564                    that aren't persistent, we should renew those as
2565                    well. */
2566                 afs_cred_get_context_creds(l, &nc->ctx);
2567
2568                 if (nc->ctx.scope == KHUI_SCOPE_CREDTYPE ||
2569                     nc->ctx.scope == KHUI_SCOPE_CRED) {
2570
2571                     ident_renew_triggered = FALSE;
2572
2573                 }
2574
2575             } else {
2576                 _report_cs1(KHERR_INFO,
2577                             L"AFS New Creds :: ident %1!p!",
2578                             _cptr(nc->identities[0]));
2579
2580                 d = (afs_dlg_data *) nct->aux;
2581                 if(!d) {
2582                     _report_cs0(KHERR_INFO,
2583                                 L"No dialog data found.  Aborting");
2584
2585                     khui_cw_set_response(nc, afs_credtype_id,
2586                                          KHUI_NC_RESPONSE_FAILED);
2587                     _end_task();
2588                     break;
2589                 }
2590
2591                 EnterCriticalSection(&d->cs);
2592
2593                 l = &d->creds;
2594
2595                 ident = nc->identities[0];
2596                 if (!ident) {
2597                     LeaveCriticalSection(&d->cs);
2598
2599                     _report_cs0(KHERR_INFO,
2600                                 L"No identity specified. Aborting");
2601
2602                     khui_cw_set_response(nc, afs_credtype_id,
2603                                          KHUI_NC_RESPONSE_FAILED);
2604
2605                     _end_task();
2606                     break;
2607                 }
2608
2609                 get_tokens = d->afs_enabled;
2610             }
2611
2612             if (!get_tokens)
2613                 goto _skip_tokens;
2614
2615             if (KHM_SUCCEEDED(kmm_get_plugin_config(AFS_PLUGIN_NAME, 0,
2616                                                     &csp_afscred)))
2617                 khc_open_space(csp_afscred, L"Cells", 0, &csp_cells);
2618
2619             /* looks like k5 worked.  Now see about getting those
2620                tokens */
2621             for(i=0; i<l->n_rows; i++) {
2622                 int code;
2623                 char cell[MAXCELLCHARS];
2624                 char realm[MAXCELLCHARS];
2625                 khm_handle ctoken;
2626                 FILETIME ft_old;
2627                 FILETIME ft_new;
2628                 time_t new_exp = 0;
2629                 khm_size cb;
2630                 khm_int32 method = AFS_TOKEN_AUTO;
2631                 khm_handle csp_cell = NULL;
2632
2633                 if (l->rows[i].flags &
2634                     (DLGROW_FLAG_DONE | DLGROW_FLAG_DELETED))
2635
2636                     continue;
2637
2638                 ZeroMemory(cell, sizeof(cell));
2639                 ZeroMemory(realm, sizeof(realm));
2640
2641                 UnicodeStrToAnsi(cell, sizeof(cell), l->rows[i].cell);
2642                 if (l->rows[i].realm != NULL)
2643                     UnicodeStrToAnsi(realm, sizeof(realm), 
2644                                      l->rows[i].realm);
2645
2646                 ZeroMemory(&ft_old, sizeof(ft_old));
2647
2648                 if (!ident_renew_triggered &&
2649                     (ctoken = afs_find_token(NULL, l->rows[i].cell))) {
2650
2651                     cb = sizeof(ft_old);
2652                     kcdb_cred_get_attr(ctoken, KCDB_ATTR_EXPIRE,
2653                                        NULL, &ft_old, &cb);
2654
2655                     kcdb_cred_release(ctoken);
2656                 }
2657
2658                 if (l->rows[i].method == AFS_TOKEN_AUTO && csp_cells &&
2659                     KHM_SUCCEEDED(khc_open_space(csp_cells,
2660                                                  l->rows[i].cell, 0,
2661                                                  &csp_cell))) {
2662
2663                     if (KHM_FAILED(khc_read_int32(csp_cell, L"Method", &method))) {
2664                         method = l->rows[i].method;
2665                     } else {
2666                         _report_cs3(KHERR_INFO,
2667                                     L"Overriding method %1!d! with global default %2!d! for cell %3!s!",
2668                                     _int32(l->rows[i].method),
2669                                     _int32(method),
2670                                     _cstr(l->rows[i].cell));
2671                         _resolve();
2672                     }
2673
2674                     khc_close_space(csp_cell);               
2675                 } else {
2676                     method = l->rows[i].method;
2677                 }
2678
2679                 _report_cs3(KHERR_INFO,
2680                             L"Getting tokens for cell %1!S! with realm %2!S! using method %3!d!",
2681                             _cstr(cell),
2682                             _cstr(realm),
2683                             _int32(method));
2684                 _resolve();
2685
2686                 /* make the call */
2687                 code = afs_klog(ident, "", cell, realm, 0, 
2688                                 method, &new_exp);
2689
2690                 _report_cs1(KHERR_INFO,
2691                             L"klog returns code %1!d!",
2692                             _int32(code));
2693
2694                 if(code) {
2695                     failed = TRUE;
2696                     l->rows[i].flags &= ~DLGROW_FLAG_DONE;
2697
2698                     if (!kherr_is_error()) {
2699                         /* failed to get tokens, but no error was reported */
2700                         _report_sr1(KHERR_ERROR, IDS_ERR_GENERAL,
2701                                     _cptr(cell));
2702                         _resolve();
2703                     }
2704
2705                 } else {
2706                     l->rows[i].flags |= DLGROW_FLAG_DONE;
2707                     succeeded = TRUE;
2708
2709                     if (new_exp &&
2710                         !ident_renew_triggered) {
2711                         TimetToFileTime(new_exp, &ft_new);
2712
2713                         if (CompareFileTime(&ft_old, &ft_new) >= 0) {
2714                             /* getting a new token didn't improve the
2715                                situation much.  We only get here if we
2716                                were trying to renew tokens. So we try
2717                                to trigger an identity renewal.  Doing
2718                                so should get us new initial tickets
2719                                which will allow us to get a better
2720                                token. */
2721
2722                             khui_action_context ctx;
2723
2724                             _reportf(L"Renewal of AFS tokens for cell %s failed to get a longer token.  Triggering identity renewal", l->rows[i].cell);
2725
2726                             khui_context_create(&ctx,
2727                                                 KHUI_SCOPE_IDENT,
2728                                                 nc->ctx.identity,
2729                                                 KCDB_CREDTYPE_INVALID,
2730                                                 NULL);
2731                             khui_action_trigger(KHUI_ACTION_RENEW_CRED,
2732                                                 &ctx);
2733
2734                             khui_context_release(&ctx);
2735
2736                             ident_renew_triggered = TRUE;
2737                         }
2738                     }
2739                 }
2740             }
2741
2742         _skip_tokens:
2743
2744             if(failed) {
2745                 /* we should indicate errors if anything went wrong */
2746                 khui_cw_set_response(nc, afs_credtype_id, 
2747                                      KHUI_NC_RESPONSE_FAILED);
2748             } else {
2749                 khui_cw_set_response(nc, afs_credtype_id,
2750                                      KHUI_NC_RESPONSE_SUCCESS);
2751             }
2752
2753             if (succeeded && nc->subtype == KMSG_CRED_RENEW_CREDS) {
2754                 afs_ident_token_set b;
2755
2756                 afs_list_tokens_internal();
2757
2758                 /* the tokens that we just acquired need adjusting to
2759                    include the realm, method and identity information
2760                    derived from the new creds operation.  this is done
2761                    in afs_adjust_token_ident_proc */
2762                 b.ident = ident;
2763                 b.l = l;
2764                 b.add_new = FALSE;
2765                 b.update_info = FALSE;
2766
2767                 kcdb_credset_apply(afs_credset, afs_adjust_token_ident_proc, 
2768                                    (void *) &b);
2769
2770                 kcdb_credset_collect(NULL, afs_credset, NULL, 
2771                                      afs_credtype_id, NULL);
2772
2773             } else if (nc->subtype == KMSG_CRED_NEW_CREDS) {
2774                 afs_ident_token_set b;
2775
2776                 afs_list_tokens_internal();
2777
2778                 /* the tokens that we just acquired need adjusting to
2779                    include the realm, method and identity information
2780                    derived from the new creds operation.  this is done
2781                    in afs_adjust_token_ident_proc */
2782                 b.ident = ident;
2783                 b.l = l;
2784                 b.add_new = FALSE;
2785                 b.update_info = FALSE;
2786
2787                 kcdb_credset_apply(afs_credset, afs_adjust_token_ident_proc, 
2788                                    (void *) &b);
2789
2790                 kcdb_credset_collect(NULL, afs_credset, NULL, 
2791                                      afs_credtype_id, NULL);
2792
2793                 afs_cred_write_ident_data(d);
2794             }
2795
2796             if (d)
2797                 LeaveCriticalSection(&d->cs);
2798
2799             if (free_tlist) {
2800                 afs_cred_free_rows(&tlist);
2801             }
2802
2803             if (csp_afscred)
2804                 khc_close_space(csp_afscred);
2805
2806             if (csp_cells)
2807                 khc_close_space(csp_cells);
2808
2809             _end_task();
2810         }
2811         break;
2812
2813     case KMSG_CRED_END:
2814         {
2815             khui_new_creds * nc;
2816             khui_new_creds_by_type * nct;
2817
2818             nc = (khui_new_creds *) vparam;
2819             khui_cw_find_type(nc, afs_credtype_id, &nct);
2820
2821             if(!nct)
2822                 break;
2823
2824             khui_cw_del_type(nc, afs_credtype_id);
2825     
2826             if (nct->name)
2827                 PFREE(nct->name);
2828             if (nct->credtext)
2829                 PFREE(nct->credtext);
2830
2831             PFREE(nct);
2832         }
2833         break;
2834     }
2835
2836     return KHM_ERROR_SUCCESS;
2837 }