2 * Copyright (c) 2005,2006 Secure Endpoints Inc.
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:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
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
29 #include<khmsgtypes.h>
36 static BOOL initialized = FALSE;
37 khm_int32 afs_credtype_id = -1;
38 khm_int32 krb5_credtype_id = -1;
39 khm_int32 krb4_credtype_id = -1;
40 khm_int32 afs_msg_type_id = -1;
41 khm_int32 afs_type_principal = -1;
42 khm_int32 afs_type_method = -1;
43 khm_int32 afs_attr_client_princ = -1;
44 khm_int32 afs_attr_server_princ = -1;
45 khm_int32 afs_attr_cell = -1;
46 khm_int32 afs_attr_method = -1;
47 khm_int32 afs_attr_realm = -1;
48 khm_handle afs_credset = NULL;
49 khm_handle afs_sub = NULL; /* AFS message subscription */
51 khm_int32 action_id_afs_help = 0;
55 afs_msg_system(khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam);
58 afs_msg_kcdb(khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam);
61 afs_msg_cred(khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam);
64 afs_msg_act(khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam);
67 afs_msg_ext(khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam);
69 /* AFS help menu extensions */
71 /* some of the functions we will be calling are only available on API
72 version 7 and above of Network Identity Manager. Since these
73 aren't critical, we allow building using API version 5 or above,
74 but conditionally use the newer functionality if the plug-in is
75 loaded by a newer version of Network Identity Manager. */
77 #if KH_VERSION_API < 7
81 /* declarations from version 7 of the API */
83 (KHMAPI * pkhui_action_lock)(void);
86 (KHMAPI * pkhui_action_unlock)(void);
89 (KHMAPI * pkhui_refresh_actions)(void);
92 (KHMAPI * khm_ui_callback)(HWND hwnd_main_wnd, void * rock);
95 (KHMAPI * pkhui_request_UI_callback)(khm_ui_callback cb,
100 /* AFS plugin callback */
102 afs_plugin_cb(khm_int32 msg_type,
103 khm_int32 msg_subtype,
107 if (msg_type == KMSG_SYSTEM)
108 return afs_msg_system(msg_subtype, uparam, vparam);
109 if (msg_type == KMSG_KCDB)
110 return afs_msg_kcdb(msg_subtype, uparam, vparam);
111 if (msg_type == KMSG_CRED)
112 return afs_msg_cred(msg_subtype, uparam, vparam);
113 if (msg_type == KMSG_ACT)
114 return afs_msg_act(msg_subtype, uparam, vparam);
115 if (msg_type == afs_msg_type_id)
116 return afs_msg_ext(msg_subtype, uparam, vparam);
118 return KHM_ERROR_SUCCESS;
121 /* ktc_principal attribute type */
125 afs_type_principal_toString(const void * d,
132 struct ktc_principal * p;
133 wchar_t sprinc[512] = L"";
136 return KHM_ERROR_INVALID_PARAM;
138 p = (struct ktc_principal *) d;
140 // assume this works.
141 afs_princ_to_string(p, sprinc, sizeof(sprinc));
142 StringCbLength(sprinc, sizeof(sprinc), &cbsize);
143 cbsize += sizeof(wchar_t);
145 if(!buffer || *cb_buf < cbsize) {
147 return KHM_ERROR_TOO_LONG;
150 StringCbCopy(buffer, *cb_buf, sprinc);
154 return KHM_ERROR_SUCCESS;
158 afs_type_principal_isValid(const void * d,
161 /*TODO: check for more inconsistencies */
162 if(cbd != sizeof(struct ktc_principal))
168 afs_type_principal_comp(const void * d1,
173 struct ktc_principal * p1 = (struct ktc_principal *) d1;
174 struct ktc_principal * p2 = (struct ktc_principal *) d2;
177 r = strcmp(p1->name, p2->name);
180 r = strcmp(p1->instance, p2->instance);
183 r = strcmp(p1->cell, p2->cell);
188 afs_type_principal_dup(const void * d_src,
193 if(!d_dst || *cbd_dst < sizeof(struct ktc_principal)) {
194 *cbd_dst = sizeof(struct ktc_principal);
195 return KHM_ERROR_TOO_LONG;
198 memcpy(d_dst, d_src, sizeof(struct ktc_principal));
199 *cbd_dst = sizeof(struct ktc_principal);
201 return KHM_ERROR_SUCCESS;
205 afs_type_method_toString(const void * data,
208 khm_size * pcb_s_buf,
210 khm_int32 * pmethod = (khm_int32 *) data;
211 wchar_t wbuf[KHUI_MAXCCH_LONG_DESC];
214 if (!data || cb_data != sizeof(khm_int32))
215 return KHM_ERROR_INVALID_PARAM;
218 if (!afs_method_describe(*pmethod, flags, wbuf, sizeof(wbuf))) {
219 LoadString(hResModule,
220 IDS_NC_METHOD_INVALID,
225 StringCbLength(wbuf, sizeof(wbuf), &cb);
226 cb += sizeof(wchar_t);
228 if (!s_buf || *pcb_s_buf < cb) {
230 return KHM_ERROR_TOO_LONG;
232 StringCbCopy(s_buf, *pcb_s_buf, wbuf);
234 return KHM_ERROR_SUCCESS;
238 /* process KMSG_SYSTEM messages */
240 afs_msg_system(khm_int32 msg_subtype,
244 khm_int32 rv = KHM_ERROR_UNKNOWN;
246 switch(msg_subtype) {
247 case KMSG_SYSTEM_INIT:
249 /* If we are building against an older SDK, we should try to
250 load newer APIs if it's available at run-time. */
251 #if KH_VERSION_API < 7
256 khm_get_lib_version(&libver, &apiver);
261 hm_netidmgr = LoadLibrary(NIMDLLNAME);
263 if (hm_netidmgr == NULL)
266 pkhui_action_lock = (void (KHMAPI *)(void))
267 GetProcAddress(hm_netidmgr, API_khui_action_lock);
268 pkhui_action_unlock = (void (KHMAPI *)(void))
269 GetProcAddress(hm_netidmgr, API_khui_action_unlock);
270 pkhui_refresh_actions = (void (KHMAPI *)(void))
271 GetProcAddress(hm_netidmgr, API_khui_refresh_actions);
272 pkhui_request_UI_callback = (khm_int32 (KHMAPI *)(khm_ui_callback, void *))
273 GetProcAddress(hm_netidmgr, API_khui_request_UI_callback);
278 /* Add the icon now. On NIM v2.x, doing so after tokens were
279 reported may result in a deadlock as we try to switch to
280 the UI thread and the UI thread is blocked on a resource
281 request to this plug-in. */
282 afs_icon_set_state(AFSICON_SERVICE_STOPPED, NULL);
284 /* Perform critical registrations and data structure
288 wchar_t buf[KCDB_MAXCCH_LONG_DESC];
291 khm_handle csp_afscred = NULL;
292 khm_int32 disable_afscreds = FALSE;
294 ZeroMemory(&ct, sizeof(ct));
295 /* first of all, register the AFS token credential type */
296 ct.id = KCDB_CREDTYPE_AUTO;
297 ct.name = AFS_CREDTYPE_NAME;
299 if(LoadString(hResModule,
302 ARRAYLENGTH(buf)) != 0) {
303 StringCbLength(buf, sizeof(buf), &cbsize);
304 cbsize += sizeof(wchar_t);
305 ct.short_desc = PMALLOC(cbsize);
306 StringCbCopy(ct.short_desc, cbsize, buf);
308 ct.short_desc = NULL;
310 if(LoadString(hResModule,
313 ARRAYLENGTH(buf)) != 0) {
314 StringCbLength(buf, sizeof(buf), &cbsize);
315 cbsize += sizeof(wchar_t);
316 ct.long_desc = PMALLOC(cbsize);
317 StringCbCopy(ct.long_desc, cbsize, buf);
321 ct.icon = LoadImage(hResModule,
322 MAKEINTRESOURCE(IDI_AFSTOKEN),
324 0, 0, LR_DEFAULTSIZE);
326 kmq_create_subscription(afs_plugin_cb, &afs_sub);
329 kcdb_credtype_register(&ct, &afs_credtype_id);
331 /* register the attribute types */
335 ZeroMemory(&type, sizeof(type));
336 type.comp = afs_type_principal_comp;
337 type.dup = afs_type_principal_dup;
338 type.isValid = afs_type_principal_isValid;
339 type.toString = afs_type_principal_toString;
340 type.name = AFS_TYPENAME_PRINCIPAL;
341 type.id = KCDB_TYPE_INVALID;
342 type.cb_max = sizeof(struct ktc_principal);
343 type.cb_min = sizeof(struct ktc_principal);
344 type.flags = KCDB_TYPE_FLAG_CB_FIXED;
346 if(KHM_FAILED(kcdb_type_register(&type,
347 &afs_type_principal)))
353 kcdb_type *ti32 = NULL;
355 kcdb_type_get_info(KCDB_TYPE_INT32, &ti32);
357 ZeroMemory(&type, sizeof(type));
358 type.comp = ti32->comp;
359 type.dup = ti32->dup;
360 type.isValid = ti32->isValid;
361 type.toString = afs_type_method_toString;
362 type.name = AFS_TYPENAME_METHOD;
363 type.id = KCDB_TYPE_INVALID;
364 type.cb_max = sizeof(khm_int32);
365 type.cb_min = sizeof(khm_int32);
366 type.flags = KCDB_TYPE_FLAG_CB_FIXED;
368 if(KHM_FAILED(kcdb_type_register(&type,
369 &afs_type_method))) {
370 kcdb_type_release_info(ti32);
374 kcdb_type_release_info(ti32);
377 /* now register the attributes */
379 wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC];
381 ZeroMemory(&att, sizeof(att));
383 att.type = KCDB_TYPE_STRING;
384 att.name = AFS_ATTRNAME_CELL;
385 LoadString(hResModule,
386 IDS_ATTR_CELL_SHORT_DESC,
388 ARRAYLENGTH(short_desc));
389 att.short_desc = short_desc;
390 att.long_desc = NULL;
391 att.id = KCDB_ATTR_INVALID;
392 att.flags = KCDB_ATTR_FLAG_TRANSIENT;
394 if(KHM_FAILED(rv = kcdb_attrib_register(&att,
400 wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC];
402 ZeroMemory(&att, sizeof(att));
404 att.type = KCDB_TYPE_STRING;
405 att.name = AFS_ATTRNAME_REALM;
406 LoadString(hResModule,
407 IDS_ATTR_REALM_SHORT_DESC,
409 ARRAYLENGTH(short_desc));
410 att.short_desc = short_desc;
411 att.long_desc = NULL;
412 att.id = KCDB_ATTR_INVALID;
413 att.flags = KCDB_ATTR_FLAG_TRANSIENT;
415 if(KHM_FAILED(rv = kcdb_attrib_register(&att,
421 wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC];
423 ZeroMemory(&att, sizeof(att));
425 att.type = afs_type_method;
426 att.name = AFS_ATTRNAME_METHOD;
427 LoadString(hResModule,
428 IDS_ATTR_METHOD_SHORT_DESC,
430 ARRAYLENGTH(short_desc));
431 att.short_desc = short_desc;
432 att.long_desc = NULL;
433 att.id = KCDB_ATTR_INVALID;
434 att.flags = KCDB_ATTR_FLAG_TRANSIENT;
436 if(KHM_FAILED(rv = kcdb_attrib_register(&att,
442 wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC];
444 ZeroMemory(&att, sizeof(att));
446 att.type = afs_type_principal;
447 att.name = AFS_ATTRNAME_CLIENT_PRINC;
448 LoadString(hResModule,
449 IDS_ATTR_CLIENT_PRINC_SHORT_DESC,
451 ARRAYLENGTH(short_desc));
452 att.short_desc = short_desc;
453 att.long_desc = NULL;
454 att.id = KCDB_ATTR_INVALID;
455 att.flags = KCDB_ATTR_FLAG_TRANSIENT;
457 if(KHM_FAILED(rv = kcdb_attrib_register(&att, &afs_attr_client_princ)))
462 wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC];
464 ZeroMemory(&att, sizeof(att));
466 att.type = afs_type_principal;
467 att.name = AFS_ATTRNAME_SERVER_PRINC;
468 LoadString(hResModule,
469 IDS_ATTR_SERVER_PRINC_SHORT_DESC,
470 short_desc, ARRAYLENGTH(short_desc));
471 att.short_desc = short_desc;
472 att.long_desc = NULL;
473 att.id = KCDB_ATTR_INVALID;
474 att.flags = KCDB_ATTR_FLAG_TRANSIENT;
476 if(KHM_FAILED(rv = kcdb_attrib_register(&att, &afs_attr_server_princ)))
480 /* afs_credset is our stock credentials set that we
481 use for all our credset needs (instead of creating
482 a new one every time) */
484 if(KHM_FAILED(rv = kcdb_credset_create(&afs_credset)))
487 if(KHM_FAILED(rv = kcdb_credtype_get_id(KRB5_CREDTYPE_NAME,
491 /* register the configuration nodes */
493 khui_config_node node_ident;
494 khui_config_node_reg reg;
495 wchar_t wshort_desc[KHUI_MAXCCH_SHORT_DESC];
496 wchar_t wlong_desc[KHUI_MAXCCH_LONG_DESC];
498 if (KHM_FAILED(rv = khui_cfg_open(NULL,
503 ZeroMemory(®, sizeof(reg));
504 reg.name = AFS_CONFIG_NODE_MAIN;
505 reg.short_desc = wshort_desc;
506 reg.long_desc = wlong_desc;
507 reg.h_module = hResModule;
508 reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_AFS);
509 reg.dlg_proc = afs_cfg_main_proc;
511 LoadString(hResModule, IDS_CFG_MAIN_LONG,
512 wlong_desc, ARRAYLENGTH(wlong_desc));
513 LoadString(hResModule, IDS_CFG_MAIN_SHORT,
514 wshort_desc, ARRAYLENGTH(wshort_desc));
516 khui_cfg_register(NULL, ®);
518 ZeroMemory(®, sizeof(reg));
519 reg.name = AFS_CONFIG_NODE_IDS;
520 reg.short_desc = wshort_desc;
521 reg.long_desc = wshort_desc;
522 reg.h_module = hResModule;
523 reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDS_TAB);
524 reg.dlg_proc = afs_cfg_ids_proc;
525 reg.flags = KHUI_CNFLAG_SUBPANEL;
526 LoadString(hResModule, IDS_CFG_IDS_TAB,
527 wshort_desc, ARRAYLENGTH(wshort_desc));
529 khui_cfg_register(node_ident, ®);
531 ZeroMemory(®, sizeof(reg));
532 reg.name = AFS_CONFIG_NODE_ID;
533 reg.short_desc = wshort_desc;
534 reg.long_desc = wshort_desc;
535 reg.h_module = hResModule;
536 reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_ID_TAB);
537 reg.dlg_proc = afs_cfg_id_proc;
538 reg.flags = KHUI_CNFLAG_SUBPANEL | KHUI_CNFLAG_PLURAL;
539 LoadString(hResModule, IDS_CFG_ID_TAB,
540 wshort_desc, ARRAYLENGTH(wshort_desc));
542 khui_cfg_register(node_ident, ®);
545 /* and register the AFS message type */
546 rv = kmq_register_type(AFS_MSG_TYPENAME, &afs_msg_type_id);
548 if (KHM_SUCCEEDED(rv))
549 kmq_subscribe(afs_msg_type_id, afs_plugin_cb);
551 /* if the configuration is set to disable afscreds.exe,
552 then we look for the shortcut and remove it if
554 if (KHM_SUCCEEDED(kmm_get_plugin_config(AFS_PLUGIN_NAME,
557 wchar_t wpath[MAX_PATH];
559 khc_read_int32(csp_afscred, L"Disableafscreds",
562 if (disable_afscreds &&
563 afs_cfg_get_afscreds_shortcut(wpath)) {
569 khc_close_space(csp_afscred);
572 /* try to register the "AFS Help" menu item, if
575 khm_handle h_sub = NULL;
576 wchar_t short_desc[KHUI_MAXCCH_SHORT_DESC];
577 wchar_t long_desc[KHUI_MAXCCH_LONG_DESC];
579 #if KH_VERSION_API < 7
580 if (pkhui_action_lock == NULL ||
581 pkhui_action_unlock == NULL ||
582 pkhui_refresh_actions == NULL ||
583 pkhui_request_UI_callback == NULL)
588 kmq_create_subscription(afs_plugin_cb, &h_sub);
590 LoadString(hResModule, IDS_ACTION_AFS_HELP,
591 short_desc, ARRAYLENGTH(short_desc));
592 LoadString(hResModule, IDS_ACTION_AFS_HELP_TT,
593 long_desc, ARRAYLENGTH(long_desc));
595 action_id_afs_help = khui_action_create(NULL,
599 KHUI_ACTIONTYPE_TRIGGER,
602 if (action_id_afs_help != 0) {
605 khui_menu_def * help_menu;
606 khm_boolean refresh = FALSE;
610 help_menu = khui_find_menu(KHUI_MENU_HELP);
612 s = khui_menu_get_size(help_menu);
614 for (i=0; i < s; i++) {
615 khui_action_ref * aref;
617 aref = khui_menu_get_action(help_menu, i);
619 if (aref && !(aref->flags & KHUI_ACTIONREF_PACTION) &&
620 aref->action == KHUI_ACTION_HELP_INDEX) {
622 khui_menu_insert_action(help_menu,
632 khui_action_unlock();
635 khui_refresh_actions();
638 #if KH_VERSION_API < 7
646 PFREE(ct.short_desc);
650 /* now that the critical stuff is done, we move on to the
651 non-critical stuff */
652 if(KHM_SUCCEEDED(rv)) {
655 /* obtain existing tokens */
659 /* define this so that if there are no TGT's, we don't
660 deadlock trying to open a new creds dialog from within the
662 SetEnvironmentVariable(L"KERBEROSLOGIN_NEVER_PROMPT", L"1");
665 /* end of KMSG_SYSTEM_INIT */
667 case KMSG_SYSTEM_EXIT:
671 /* Try to remove the AFS plug-in action from Help menu if it
672 was successfully registered. Also, delete the action. */
673 if (action_id_afs_help != 0) {
675 khui_menu_def * help_menu;
676 khm_boolean menu_changed = FALSE;
680 help_menu = khui_find_menu(KHUI_MENU_HELP);
685 s = khui_menu_get_size(help_menu);
686 for (i=0; i < s; i++) {
687 khui_action_ref * aref = khui_menu_get_action(help_menu, i);
689 if (aref && !(aref->flags & KHUI_ACTIONREF_PACTION) &&
690 aref->action == action_id_afs_help) {
692 khui_menu_remove_action(help_menu, i);
699 khui_action_delete(action_id_afs_help);
701 khui_action_unlock();
704 khui_refresh_actions();
706 action_id_afs_help = 0;
709 if (afs_msg_type_id != -1) {
710 kmq_unsubscribe(afs_msg_type_id, afs_plugin_cb);
711 kmq_unregister_type(afs_msg_type_id);
713 if(afs_credtype_id >= 0) {
714 kcdb_credtype_unregister(afs_credtype_id);
717 if(afs_attr_client >= 0) {
718 kcdb_attrib_unregister(afs_attr_client);
721 if(afs_attr_cell >= 0) {
722 kcdb_attrib_unregister(afs_attr_cell);
724 if(afs_attr_realm >= 0) {
725 kcdb_attrib_unregister(afs_attr_realm);
727 if(afs_attr_method >= 0) {
728 kcdb_attrib_unregister(afs_attr_method);
730 if(afs_attr_client_princ >= 0) {
731 kcdb_attrib_unregister(afs_attr_client_princ);
733 if(afs_attr_server_princ >= 0) {
734 kcdb_attrib_unregister(afs_attr_server_princ);
736 if(afs_type_principal >= 0) {
737 kcdb_type_unregister(afs_type_principal);
739 if(afs_type_method >= 0) {
740 kcdb_type_unregister(afs_type_method);
744 kcdb_credset_delete(afs_credset);
746 /* afs_sub doesn't need to be deleted. That is taken care
747 of when unregistering the afs cred type */
750 #if KH_VERSION_API < 7
752 FreeLibrary(hm_netidmgr);
754 pkhui_action_lock = NULL;
755 pkhui_action_unlock = NULL;
756 pkhui_refresh_actions = NULL;
757 pkhui_request_UI_callback = NULL;
760 rv = KHM_ERROR_SUCCESS;
762 /* end of KMSG_SYSTEM_EXIT */
767 /* process KMSG_KCDB messages */
769 afs_msg_kcdb(khm_int32 msg_subtype,
773 khm_int32 rv = KHM_ERROR_SUCCESS;
775 /* we don't really do anything with this yet */
777 switch(msg_subtype) {
786 static khm_int32 KHMAPI
787 afs_cred_destroy_proc(khm_handle cred, void * rock) {
790 if (KHM_FAILED(kcdb_cred_get_type(cred, &t)) ||
791 t != afs_credtype_id)
792 return KHM_ERROR_SUCCESS;
794 afs_unlog_cred(cred);
796 return KHM_ERROR_SUCCESS;
799 /* process KMSG_CRED messages */
801 afs_msg_cred(khm_int32 msg_subtype,
805 khm_int32 rv = KHM_ERROR_SUCCESS;
807 switch(msg_subtype) {
808 case KMSG_CRED_REFRESH:
812 case KMSG_CRED_DESTROY_CREDS:
814 khui_action_context * ctx;
816 ctx = (khui_action_context *) vparam;
820 _report_cs0(KHERR_INFO, L"Destroying AFS Tokens");
823 kcdb_credset_apply(ctx->credset,
824 afs_cred_destroy_proc,
834 if (IS_CRED_ACQ_MSG(msg_subtype))
835 return afs_msg_newcred(msg_subtype, uparam, vparam);
843 help_launcher(HWND hwnd_main, void * rock) {
844 afs_html_help(hwnd_main, NULL, HH_DISPLAY_TOC, 0);
846 return KHM_ERROR_SUCCESS;
850 afs_msg_act(khm_int32 msg_subtype,
854 khm_int32 rv = KHM_ERROR_SUCCESS;
856 if (msg_subtype == KMSG_ACT_ACTIVATE &&
857 uparam == (khm_ui_4)action_id_afs_help) {
859 khui_request_UI_callback(help_launcher, NULL);