Windows: permit aklog to build with krb4 support and roken
[openafs.git] / src / WINNT / netidmgr_plugin / afsplugin.c
1 /*
2  * Copyright (c) 2005,2006 Secure Endpoints Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without
7  * restriction, including without limitation the rights to use, copy,
8  * modify, merge, publish, distribute, sublicense, and/or sell copies
9  * of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24
25 /* $Id$ */
26
27 #include <afsconfig.h>
28 #include <afs/param.h>
29 #include <roken.h>
30
31 #include<afscred.h>
32 #include<kcreddb.h>
33 #include<khmsgtypes.h>
34 #include<kherror.h>
35 #include<khuidefs.h>
36 #include<commctrl.h>
37 #include<htmlhelp.h>
38 #include<assert.h>
39
40 static BOOL initialized = FALSE;
41 khm_int32 afs_credtype_id = -1;
42 khm_int32 krb5_credtype_id = -1;
43 khm_int32 krb4_credtype_id = -1;
44 khm_int32 afs_msg_type_id = -1;
45 khm_int32 afs_type_principal = -1;
46 khm_int32 afs_type_method = -1;
47 khm_int32 afs_attr_client_princ = -1;
48 khm_int32 afs_attr_server_princ = -1;
49 khm_int32 afs_attr_cell = -1;
50 khm_int32 afs_attr_method = -1;
51 khm_int32 afs_attr_realm = -1;
52 khm_handle afs_credset = NULL;
53 khm_handle afs_sub = NULL;      /* AFS message subscription */
54
55 khm_int32 action_id_afs_help = 0;
56
57 /* forward dcls */
58 khm_int32 KHMAPI 
59 afs_msg_system(khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam);
60
61 khm_int32 KHMAPI 
62 afs_msg_kcdb(khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam);
63
64 khm_int32 KHMAPI 
65 afs_msg_cred(khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam);
66
67 khm_int32 KHMAPI
68 afs_msg_act(khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam);
69
70 khm_int32 KHMAPI 
71 afs_msg_ext(khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam);
72
73 /* AFS help menu extensions */
74
75 /* some of the functions we will be calling are only available on API
76    version 7 and above of Network Identity Manager.  Since these
77    aren't critical, we allow building using API version 5 or above,
78    but conditionally use the newer functionality if the plug-in is
79    loaded by a newer version of Network Identity Manager. */
80
81 #if KH_VERSION_API < 7
82
83 HMODULE hm_netidmgr;
84
85 /* declarations from version 7 of the API */
86 void
87 (KHMAPI * pkhui_action_lock)(void);
88
89 void
90 (KHMAPI * pkhui_action_unlock)(void);
91
92 void
93 (KHMAPI * pkhui_refresh_actions)(void);
94
95 typedef khm_int32
96 (KHMAPI * khm_ui_callback)(HWND hwnd_main_wnd, void * rock);
97
98 khm_int32
99 (KHMAPI * pkhui_request_UI_callback)(khm_ui_callback cb,
100                                      void * rock);
101
102 #endif
103
104 /* AFS plugin callback */
105 khm_int32 KHMAPI 
106 afs_plugin_cb(khm_int32 msg_type,
107               khm_int32 msg_subtype,
108               khm_ui_4 uparam,
109               void * vparam)
110 {
111     if (msg_type == KMSG_SYSTEM)
112         return afs_msg_system(msg_subtype, uparam, vparam);
113     if (msg_type == KMSG_KCDB)
114         return afs_msg_kcdb(msg_subtype, uparam, vparam);
115     if (msg_type == KMSG_CRED)
116         return afs_msg_cred(msg_subtype, uparam, vparam);
117     if (msg_type == KMSG_ACT)
118         return afs_msg_act(msg_subtype, uparam, vparam);
119     if (msg_type == afs_msg_type_id)
120         return afs_msg_ext(msg_subtype, uparam, vparam);
121
122     return KHM_ERROR_SUCCESS;
123 }
124
125 /* ktc_principal attribute type */
126 /* String */
127
128 khm_int32 KHMAPI 
129 afs_type_principal_toString(const void * d, 
130                             khm_size cbd, 
131                             wchar_t * buffer, 
132                             khm_size * cb_buf, 
133                             khm_int32 flags)
134 {
135     size_t cbsize;
136     struct ktc_principal * p;
137     wchar_t sprinc[512] = L"";
138
139     if(!cb_buf)
140         return KHM_ERROR_INVALID_PARAM;
141
142     p = (struct ktc_principal *) d;
143
144     // assume this works.
145     afs_princ_to_string(p, sprinc, sizeof(sprinc));
146     StringCbLength(sprinc, sizeof(sprinc), &cbsize);
147     cbsize += sizeof(wchar_t);
148
149     if(!buffer || *cb_buf < cbsize) {
150         *cb_buf = cbsize;
151         return KHM_ERROR_TOO_LONG;
152     }
153
154     StringCbCopy(buffer, *cb_buf, sprinc);
155
156     *cb_buf = cbsize;
157
158     return KHM_ERROR_SUCCESS;
159 }
160
161 khm_boolean KHMAPI 
162 afs_type_principal_isValid(const void * d,
163                            khm_size cbd)
164 {
165     /*TODO: check for more inconsistencies */
166     if(cbd != sizeof(struct ktc_principal))
167         return FALSE;
168     return TRUE;
169 }
170
171 khm_int32 KHMAPI 
172 afs_type_principal_comp(const void * d1,
173                         khm_size cbd1,
174                         const void * d2,
175                         khm_size cbd2)
176 {
177     struct ktc_principal * p1 = (struct ktc_principal *) d1;
178     struct ktc_principal * p2 = (struct ktc_principal *) d2;
179     int r;
180
181     r = strcmp(p1->name, p2->name);
182     if(r != 0)
183         return r;
184     r = strcmp(p1->instance, p2->instance);
185     if(r != 0)
186         return r;
187     r = strcmp(p1->cell, p2->cell);
188     return r;
189 }
190
191 khm_int32 KHMAPI 
192 afs_type_principal_dup(const void * d_src,
193                        khm_size cbd_src,
194                        void * d_dst,
195                        khm_size * cbd_dst)
196 {
197     if(!d_dst || *cbd_dst < sizeof(struct ktc_principal)) {
198         *cbd_dst = sizeof(struct ktc_principal);
199         return KHM_ERROR_TOO_LONG;
200     }
201
202     memcpy(d_dst, d_src, sizeof(struct ktc_principal));
203     *cbd_dst = sizeof(struct ktc_principal);
204
205     return KHM_ERROR_SUCCESS;
206 }
207
208 khm_int32 KHMAPI
209 afs_type_method_toString(const void * data,
210                          khm_size     cb_data,
211                          wchar_t *    s_buf,
212                          khm_size *   pcb_s_buf,
213                          khm_int32    flags) {
214     khm_int32 * pmethod = (khm_int32 *) data;
215     wchar_t wbuf[KHUI_MAXCCH_LONG_DESC];
216     khm_size cb;
217
218     if (!data || cb_data != sizeof(khm_int32))
219         return KHM_ERROR_INVALID_PARAM;
220
221     wbuf[0] = L'\0';
222     if (!afs_method_describe(*pmethod, flags, wbuf, sizeof(wbuf))) {
223         LoadString(hResModule,
224                    IDS_NC_METHOD_INVALID,
225                    wbuf,
226                    ARRAYLENGTH(wbuf));
227     }
228
229     StringCbLength(wbuf, sizeof(wbuf), &cb);
230     cb += sizeof(wchar_t);
231
232     if (!s_buf || *pcb_s_buf < cb) {
233         *pcb_s_buf = cb;
234         return KHM_ERROR_TOO_LONG;
235     } else {
236         StringCbCopy(s_buf, *pcb_s_buf, wbuf);
237         *pcb_s_buf = cb;
238         return KHM_ERROR_SUCCESS;
239     }
240 }
241
242 /* process KMSG_SYSTEM messages */
243 khm_int32 KHMAPI 
244 afs_msg_system(khm_int32 msg_subtype, 
245                khm_ui_4 uparam, 
246                void * vparam)
247 {
248     khm_int32 rv = KHM_ERROR_UNKNOWN;
249
250     switch(msg_subtype) {
251     case KMSG_SYSTEM_INIT:
252
253         /* If we are building against an older SDK, we should try to
254            load newer APIs if it's available at run-time. */
255 #if KH_VERSION_API < 7
256         do {
257             khm_version libver;
258             khm_ui_4 apiver;
259
260             khm_get_lib_version(&libver, &apiver);
261
262             if (apiver < 7)
263                 break;
264
265             hm_netidmgr = LoadLibrary(NIMDLLNAME);
266
267             if (hm_netidmgr == NULL)
268                 break;
269
270             pkhui_action_lock = (void (KHMAPI *)(void))
271                 GetProcAddress(hm_netidmgr, API_khui_action_lock);
272             pkhui_action_unlock = (void (KHMAPI *)(void))
273                 GetProcAddress(hm_netidmgr, API_khui_action_unlock);
274             pkhui_refresh_actions = (void (KHMAPI *)(void))
275                 GetProcAddress(hm_netidmgr, API_khui_refresh_actions);
276             pkhui_request_UI_callback = (khm_int32 (KHMAPI *)(khm_ui_callback, void *))
277                 GetProcAddress(hm_netidmgr, API_khui_request_UI_callback);
278
279         } while (FALSE);
280 #endif
281
282         /* Add the icon now.  On NIM v2.x, doing so after tokens were
283            reported may result in a deadlock as we try to switch to
284            the UI thread and the UI thread is blocked on a resource
285            request to this plug-in. */
286         afs_icon_set_state(AFSICON_SERVICE_STOPPED, NULL);
287
288         /* Perform critical registrations and data structure
289            initalization */
290         {
291             kcdb_credtype ct;
292             wchar_t buf[KCDB_MAXCCH_LONG_DESC];
293             size_t cbsize;
294             kcdb_attrib att;
295             khm_handle csp_afscred = NULL;
296             khm_int32 disable_afscreds = FALSE;
297
298             ZeroMemory(&ct, sizeof(ct));
299             /* first of all, register the AFS token credential type */
300             ct.id = KCDB_CREDTYPE_AUTO;
301             ct.name = AFS_CREDTYPE_NAME;
302
303             if(LoadString(hResModule, 
304                           IDS_AFS_SHORT_DESC, 
305                           buf, 
306                           ARRAYLENGTH(buf)) != 0) {
307                 StringCbLength(buf, sizeof(buf), &cbsize);
308                 cbsize += sizeof(wchar_t);
309                 ct.short_desc = PMALLOC(cbsize);
310                 StringCbCopy(ct.short_desc, cbsize, buf);
311             } else
312                 ct.short_desc = NULL;
313
314             if(LoadString(hResModule, 
315                           IDS_AFS_LONG_DESC, 
316                           buf, 
317                           ARRAYLENGTH(buf)) != 0) {
318                 StringCbLength(buf, sizeof(buf), &cbsize);
319                 cbsize += sizeof(wchar_t);
320                 ct.long_desc = PMALLOC(cbsize);
321                 StringCbCopy(ct.long_desc, cbsize, buf);
322             } else
323                 ct.long_desc = NULL;
324
325             ct.icon = LoadImage(hResModule, 
326                                 MAKEINTRESOURCE(IDI_AFSTOKEN), 
327                                 IMAGE_ICON, 
328                                 0, 0, LR_DEFAULTSIZE);
329
330             kmq_create_subscription(afs_plugin_cb, &afs_sub);
331             ct.sub = afs_sub;
332
333             kcdb_credtype_register(&ct, &afs_credtype_id);
334
335             /* register the attribute types */
336             {
337                 kcdb_type type;
338
339                 ZeroMemory(&type, sizeof(type));
340                 type.comp = afs_type_principal_comp;
341                 type.dup = afs_type_principal_dup;
342                 type.isValid = afs_type_principal_isValid;
343                 type.toString = afs_type_principal_toString;
344                 type.name = AFS_TYPENAME_PRINCIPAL;
345                 type.id = KCDB_TYPE_INVALID;
346                 type.cb_max = sizeof(struct ktc_principal);
347                 type.cb_min = sizeof(struct ktc_principal);
348                 type.flags = KCDB_TYPE_FLAG_CB_FIXED;
349
350                 if(KHM_FAILED(kcdb_type_register(&type, 
351                                                  &afs_type_principal)))
352                     goto _exit_init;
353             }
354
355             {
356                 kcdb_type type;
357                 kcdb_type *ti32 = NULL;
358
359                 kcdb_type_get_info(KCDB_TYPE_INT32, &ti32);
360
361                 ZeroMemory(&type, sizeof(type));
362                 type.comp = ti32->comp;
363                 type.dup = ti32->dup;
364                 type.isValid = ti32->isValid;
365                 type.toString = afs_type_method_toString;
366                 type.name = AFS_TYPENAME_METHOD;
367                 type.id = KCDB_TYPE_INVALID;
368                 type.cb_max = sizeof(khm_int32);
369                 type.cb_min = sizeof(khm_int32);
370                 type.flags = KCDB_TYPE_FLAG_CB_FIXED;
371
372                 if(KHM_FAILED(kcdb_type_register(&type, 
373                                                  &afs_type_method))) {
374                     kcdb_type_release_info(ti32);
375                     goto _exit_init;
376                 }
377
378                 kcdb_type_release_info(ti32);
379             }
380
381             /* now register the attributes */
382             {
383                 wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC];
384                     
385                 ZeroMemory(&att, sizeof(att));
386
387                 att.type = KCDB_TYPE_STRING;
388                 att.name = AFS_ATTRNAME_CELL;
389                 LoadString(hResModule, 
390                            IDS_ATTR_CELL_SHORT_DESC, 
391                            short_desc, 
392                            ARRAYLENGTH(short_desc));
393                 att.short_desc = short_desc;
394                 att.long_desc = NULL;
395                 att.id = KCDB_ATTR_INVALID;
396                 att.flags = KCDB_ATTR_FLAG_TRANSIENT;
397                     
398                 if(KHM_FAILED(rv = kcdb_attrib_register(&att, 
399                                                         &afs_attr_cell)))
400                     goto _exit_init;
401             }
402
403             {
404                 wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC];
405                     
406                 ZeroMemory(&att, sizeof(att));
407
408                 att.type = KCDB_TYPE_STRING;
409                 att.name = AFS_ATTRNAME_REALM;
410                 LoadString(hResModule, 
411                            IDS_ATTR_REALM_SHORT_DESC, 
412                            short_desc, 
413                            ARRAYLENGTH(short_desc));
414                 att.short_desc = short_desc;
415                 att.long_desc = NULL;
416                 att.id = KCDB_ATTR_INVALID;
417                 att.flags = KCDB_ATTR_FLAG_TRANSIENT;
418                     
419                 if(KHM_FAILED(rv = kcdb_attrib_register(&att, 
420                                                         &afs_attr_realm)))
421                     goto _exit_init;
422             }
423
424             {
425                 wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC];
426                     
427                 ZeroMemory(&att, sizeof(att));
428
429                 att.type = afs_type_method;
430                 att.name = AFS_ATTRNAME_METHOD;
431                 LoadString(hResModule, 
432                            IDS_ATTR_METHOD_SHORT_DESC, 
433                            short_desc, 
434                            ARRAYLENGTH(short_desc));
435                 att.short_desc = short_desc;
436                 att.long_desc = NULL;
437                 att.id = KCDB_ATTR_INVALID;
438                 att.flags = KCDB_ATTR_FLAG_TRANSIENT;
439                     
440                 if(KHM_FAILED(rv = kcdb_attrib_register(&att, 
441                                                         &afs_attr_method)))
442                     goto _exit_init;
443             }
444
445             {
446                 wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC];
447
448                 ZeroMemory(&att, sizeof(att));
449
450                 att.type = afs_type_principal;
451                 att.name = AFS_ATTRNAME_CLIENT_PRINC;
452                 LoadString(hResModule, 
453                            IDS_ATTR_CLIENT_PRINC_SHORT_DESC, 
454                            short_desc, 
455                            ARRAYLENGTH(short_desc));
456                 att.short_desc = short_desc;
457                 att.long_desc = NULL;
458                 att.id = KCDB_ATTR_INVALID;
459                 att.flags = KCDB_ATTR_FLAG_TRANSIENT;
460                     
461                 if(KHM_FAILED(rv = kcdb_attrib_register(&att, &afs_attr_client_princ)))
462                     goto _exit_init;
463             }
464
465             {
466                 wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC];
467
468                 ZeroMemory(&att, sizeof(att));
469
470                 att.type = afs_type_principal;
471                 att.name = AFS_ATTRNAME_SERVER_PRINC;
472                 LoadString(hResModule, 
473                            IDS_ATTR_SERVER_PRINC_SHORT_DESC, 
474                            short_desc, ARRAYLENGTH(short_desc));
475                 att.short_desc = short_desc;
476                 att.long_desc = NULL;
477                 att.id = KCDB_ATTR_INVALID;
478                 att.flags = KCDB_ATTR_FLAG_TRANSIENT;
479                     
480                 if(KHM_FAILED(rv = kcdb_attrib_register(&att, &afs_attr_server_princ)))
481                     goto _exit_init;
482             }
483
484             /* afs_credset is our stock credentials set that we
485                use for all our credset needs (instead of creating
486                a new one every time) */
487
488             if(KHM_FAILED(rv = kcdb_credset_create(&afs_credset)))
489                 goto _exit_init;
490
491             if(KHM_FAILED(rv = kcdb_credtype_get_id(KRB5_CREDTYPE_NAME,
492                                                     &krb5_credtype_id)))
493                 goto _exit_init;
494
495             /* register the configuration nodes */
496             {
497                 khui_config_node node_ident;
498                 khui_config_node_reg reg;
499                 wchar_t wshort_desc[KHUI_MAXCCH_SHORT_DESC];
500                 wchar_t wlong_desc[KHUI_MAXCCH_LONG_DESC];
501
502                 if (KHM_FAILED(rv = khui_cfg_open(NULL,
503                                                   L"KhmIdentities",
504                                                   &node_ident)))
505                     goto _exit_init;
506
507                 ZeroMemory(&reg, sizeof(reg));
508                 reg.name = AFS_CONFIG_NODE_MAIN;
509                 reg.short_desc = wshort_desc;
510                 reg.long_desc = wlong_desc;
511                 reg.h_module = hResModule;
512                 reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_AFS);
513                 reg.dlg_proc = afs_cfg_main_proc;
514                 reg.flags = 0;
515                 LoadString(hResModule, IDS_CFG_MAIN_LONG,
516                            wlong_desc, ARRAYLENGTH(wlong_desc));
517                 LoadString(hResModule, IDS_CFG_MAIN_SHORT,
518                            wshort_desc, ARRAYLENGTH(wshort_desc));
519
520                 khui_cfg_register(NULL, &reg);
521
522                 ZeroMemory(&reg, sizeof(reg));
523                 reg.name = AFS_CONFIG_NODE_IDS;
524                 reg.short_desc = wshort_desc;
525                 reg.long_desc = wshort_desc;
526                 reg.h_module = hResModule;
527                 reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDS_TAB);
528                 reg.dlg_proc = afs_cfg_ids_proc;
529                 reg.flags = KHUI_CNFLAG_SUBPANEL;
530                 LoadString(hResModule, IDS_CFG_IDS_TAB,
531                            wshort_desc, ARRAYLENGTH(wshort_desc));
532
533                 khui_cfg_register(node_ident, &reg);
534
535                 ZeroMemory(&reg, sizeof(reg));
536                 reg.name = AFS_CONFIG_NODE_ID;
537                 reg.short_desc = wshort_desc;
538                 reg.long_desc = wshort_desc;
539                 reg.h_module = hResModule;
540                 reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_ID_TAB);
541                 reg.dlg_proc = afs_cfg_id_proc;
542                 reg.flags = KHUI_CNFLAG_SUBPANEL | KHUI_CNFLAG_PLURAL;
543                 LoadString(hResModule, IDS_CFG_ID_TAB,
544                            wshort_desc, ARRAYLENGTH(wshort_desc));
545
546                 khui_cfg_register(node_ident, &reg);
547             }
548
549             /* and register the AFS message type */
550             rv = kmq_register_type(AFS_MSG_TYPENAME, &afs_msg_type_id);
551
552             if (KHM_SUCCEEDED(rv))
553                 kmq_subscribe(afs_msg_type_id, afs_plugin_cb);
554
555             /* if the configuration is set to disable afscreds.exe,
556                then we look for the shortcut and remove it if
557                found. */
558             if (KHM_SUCCEEDED(kmm_get_plugin_config(AFS_PLUGIN_NAME,
559                                                     0,
560                                                     &csp_afscred))) {
561                 wchar_t wpath[MAX_PATH];
562
563                 khc_read_int32(csp_afscred, L"Disableafscreds",
564                                &disable_afscreds);
565
566                 if (disable_afscreds &&
567                     afs_cfg_get_afscreds_shortcut(wpath)) {
568
569                     DeleteFile(wpath);
570
571                 }
572
573                 khc_close_space(csp_afscred);
574             }
575
576             /* try to register the "AFS Help" menu item, if
577                possible */
578             {
579                 khm_handle h_sub = NULL;
580                 wchar_t short_desc[KHUI_MAXCCH_SHORT_DESC];
581                 wchar_t long_desc[KHUI_MAXCCH_LONG_DESC];
582
583 #if KH_VERSION_API < 7
584                 if (pkhui_action_lock == NULL ||
585                     pkhui_action_unlock == NULL ||
586                     pkhui_refresh_actions == NULL ||
587                     pkhui_request_UI_callback == NULL)
588
589                     goto no_custom_help;
590 #endif
591
592                 kmq_create_subscription(afs_plugin_cb, &h_sub);
593
594                 LoadString(hResModule, IDS_ACTION_AFS_HELP,
595                            short_desc, ARRAYLENGTH(short_desc));
596                 LoadString(hResModule, IDS_ACTION_AFS_HELP_TT,
597                            long_desc, ARRAYLENGTH(long_desc));
598
599                 action_id_afs_help = khui_action_create(NULL,
600                                                         short_desc,
601                                                         long_desc,
602                                                         NULL,
603                                                         KHUI_ACTIONTYPE_TRIGGER,
604                                                         h_sub);
605
606                 if (action_id_afs_help != 0) {
607                     khm_size s;
608                     khm_size i;
609                     khui_menu_def * help_menu;
610                     khm_boolean refresh = FALSE;
611
612                     khui_action_lock();
613
614                     help_menu = khui_find_menu(KHUI_MENU_HELP);
615                     if (help_menu) {
616                         s = khui_menu_get_size(help_menu);
617
618                         for (i=0; i < s; i++) {
619                             khui_action_ref * aref;
620
621                             aref = khui_menu_get_action(help_menu, i);
622
623                             if (aref && !(aref->flags & KHUI_ACTIONREF_PACTION) &&
624                                 aref->action == KHUI_ACTION_HELP_INDEX) {
625
626                                 khui_menu_insert_action(help_menu,
627                                                         i + 1,
628                                                         action_id_afs_help,
629                                                         0);
630                                 refresh = TRUE;
631                                 break;
632                             }
633                         }
634                     }
635
636                     khui_action_unlock();
637
638                     if (refresh)
639                         khui_refresh_actions();
640                 }
641
642 #if KH_VERSION_API < 7
643             no_custom_help:
644                 ;
645 #endif
646             }
647
648         _exit_init:
649             if(ct.short_desc)
650                 PFREE(ct.short_desc);
651             if(ct.long_desc)
652                 PFREE(ct.long_desc);
653         }
654         /* now that the critical stuff is done, we move on to the
655            non-critical stuff */
656         if(KHM_SUCCEEDED(rv)) {
657             initialized = TRUE;
658
659             /* obtain existing tokens */
660             afs_list_tokens();
661         }
662
663         /* define this so that if there are no TGT's, we don't
664            deadlock trying to open a new creds dialog from within the
665            new creds dialog. */
666         SetEnvironmentVariable(L"KERBEROSLOGIN_NEVER_PROMPT", L"1");
667
668         break;
669         /* end of KMSG_SYSTEM_INIT */
670
671     case KMSG_SYSTEM_EXIT:
672
673         afs_remove_icon();
674
675         /* Try to remove the AFS plug-in action from Help menu if it
676            was successfully registered.  Also, delete the action. */
677         if (action_id_afs_help != 0) {
678
679             khui_menu_def * help_menu;
680             khm_boolean menu_changed = FALSE;
681
682             khui_action_lock();
683
684             help_menu = khui_find_menu(KHUI_MENU_HELP);
685             if (help_menu) {
686                 khm_size s;
687                 khm_size i;
688
689                 s = khui_menu_get_size(help_menu);
690                 for (i=0; i < s; i++) {
691                     khui_action_ref * aref = khui_menu_get_action(help_menu, i);
692
693                     if (aref && !(aref->flags & KHUI_ACTIONREF_PACTION) &&
694                         aref->action == action_id_afs_help) {
695
696                         khui_menu_remove_action(help_menu, i);
697                         menu_changed = TRUE;
698                         break;
699                     }
700                 }
701             }
702
703             khui_action_delete(action_id_afs_help);
704
705             khui_action_unlock();
706
707             if (menu_changed)
708                 khui_refresh_actions();
709
710             action_id_afs_help = 0;
711         }
712
713         if (afs_msg_type_id != -1) {
714             kmq_unsubscribe(afs_msg_type_id, afs_plugin_cb);
715             kmq_unregister_type(afs_msg_type_id);
716         }
717         if(afs_credtype_id >= 0) {
718             kcdb_credtype_unregister(afs_credtype_id);
719         }
720 #if 0
721         if(afs_attr_client >= 0) {
722             kcdb_attrib_unregister(afs_attr_client);
723         }
724 #endif
725         if(afs_attr_cell >= 0) {
726             kcdb_attrib_unregister(afs_attr_cell);
727         }
728         if(afs_attr_realm >= 0) {
729             kcdb_attrib_unregister(afs_attr_realm);
730         }
731         if(afs_attr_method >= 0) {
732             kcdb_attrib_unregister(afs_attr_method);
733         }
734         if(afs_attr_client_princ >= 0) {
735             kcdb_attrib_unregister(afs_attr_client_princ);
736         }
737         if(afs_attr_server_princ >= 0) {
738             kcdb_attrib_unregister(afs_attr_server_princ);
739         }
740         if(afs_type_principal >= 0) {
741             kcdb_type_unregister(afs_type_principal);
742         }
743         if(afs_type_method >= 0) {
744             kcdb_type_unregister(afs_type_method);
745         }
746         initialized = FALSE;
747         if(afs_credset)
748             kcdb_credset_delete(afs_credset);
749
750         /* afs_sub doesn't need to be deleted.  That is taken care
751            of when unregistering the afs cred type */
752         afs_sub = NULL;
753
754 #if KH_VERSION_API < 7
755         if (hm_netidmgr)
756             FreeLibrary(hm_netidmgr);
757
758         pkhui_action_lock = NULL;
759         pkhui_action_unlock = NULL;
760         pkhui_refresh_actions = NULL;
761         pkhui_request_UI_callback = NULL;
762 #endif
763
764         rv = KHM_ERROR_SUCCESS;
765         break;
766         /* end of KMSG_SYSTEM_EXIT */
767     }
768     return rv;
769 }
770
771 /* process KMSG_KCDB messages */
772 khm_int32 KHMAPI 
773 afs_msg_kcdb(khm_int32 msg_subtype, 
774              khm_ui_4 uparam, 
775              void * vparam)
776 {
777     khm_int32 rv = KHM_ERROR_SUCCESS;
778
779     /* we don't really do anything with this yet */
780 #if 0
781     switch(msg_subtype) {
782     }
783 #endif
784
785     return rv;
786 }
787
788
789
790 static khm_int32 KHMAPI
791 afs_cred_destroy_proc(khm_handle cred, void * rock) {
792     khm_int32 t;
793
794     if (KHM_FAILED(kcdb_cred_get_type(cred, &t)) ||
795         t != afs_credtype_id)
796         return KHM_ERROR_SUCCESS;
797
798     afs_unlog_cred(cred);
799
800     return KHM_ERROR_SUCCESS;
801 }
802
803 /* process KMSG_CRED messages */
804 khm_int32 KHMAPI 
805 afs_msg_cred(khm_int32 msg_subtype, 
806              khm_ui_4 uparam, 
807              void * vparam)
808 {
809     khm_int32 rv = KHM_ERROR_SUCCESS;
810
811     switch(msg_subtype) {
812     case KMSG_CRED_REFRESH:
813         afs_list_tokens();
814         break;
815
816     case KMSG_CRED_DESTROY_CREDS:
817         {
818             khui_action_context * ctx;
819
820             ctx = (khui_action_context *) vparam;
821
822             if (ctx->credset) {
823                 _begin_task(0);
824                 _report_cs0(KHERR_INFO, L"Destroying AFS Tokens");
825                 _describe();
826
827                 kcdb_credset_apply(ctx->credset,
828                                    afs_cred_destroy_proc,
829                                    NULL);
830
831                 _end_task();
832             }
833         }
834         break;
835
836     default:
837
838         if (IS_CRED_ACQ_MSG(msg_subtype))
839             return afs_msg_newcred(msg_subtype, uparam, vparam);
840     }
841
842     return rv;
843 }
844
845
846 khm_int32 KHMAPI
847 help_launcher(HWND hwnd_main, void * rock) {
848     afs_html_help(hwnd_main, NULL, HH_DISPLAY_TOC, 0);
849
850     return KHM_ERROR_SUCCESS;
851 }
852
853 khm_int32 KHMAPI 
854 afs_msg_act(khm_int32 msg_subtype, 
855             khm_ui_4 uparam, 
856             void * vparam)
857 {
858     khm_int32 rv = KHM_ERROR_SUCCESS;
859
860     if (msg_subtype == KMSG_ACT_ACTIVATE &&
861         uparam == (khm_ui_4)action_id_afs_help) {
862
863         khui_request_UI_callback(help_launcher, NULL);
864
865     }
866
867     return rv;
868 }