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