KHMEXP khm_int32 KHMAPI kmm_get_plugin_config(wchar_t * plugin, khm_int32 flags, khm_handle * result) { khm_handle csplugins; khm_handle csplugin; khm_int32 rv; if(!plugin || wcschr(plugin, L'/') || wcschr(plugin, L'\\')) return KHM_ERROR_INVALID_PARAM; if(KHM_FAILED(kmm_get_plugins_config(flags, &csplugins))) return KHM_ERROR_UNKNOWN; rv = khc_open_space(csplugins, plugin, flags, &csplugin); *result = csplugin; khc_close_space(csplugins); return rv; }
/* called by the NetIDMgr module manager */ KHMEXP_EXP khm_int32 KHMAPI init_module(kmm_module h_module) { khm_int32 rv = KHM_ERROR_SUCCESS; kmm_plugin_reg pi; wchar_t buf[256]; h_khModule = h_module; rv = kmm_set_locale_info(h_module, locales, n_locales); if(KHM_SUCCEEDED(rv)) { hResModule = kmm_get_resource_hmodule(h_module); } else goto _exit; k5_commctl_version = khm_get_commctl_version(NULL); /* register the plugin */ ZeroMemory(&pi, sizeof(pi)); pi.name = KRB5_PLUGIN_NAME; pi.type = KHM_PITYPE_CRED; pi.icon = LoadImage(hResModule, MAKEINTRESOURCE(IDI_PLUGIN), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR | LR_DEFAULTSIZE); pi.flags = 0; pi.msg_proc = k5_msg_callback; pi.description = buf; pi.dependencies = NULL; LoadString(hResModule, IDS_PLUGIN_DESC, buf, ARRAYLENGTH(buf)); kmm_provide_plugin(h_module, &pi); ZeroMemory(&pi, sizeof(pi)); pi.name = KRB5_IDENTPRO_NAME; pi.type = KHM_PITYPE_IDENT; pi.icon = LoadImage(hResModule, MAKEINTRESOURCE(IDI_PLUGIN), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR | LR_DEFAULTSIZE); pi.flags = 0; pi.msg_proc = k5_ident_callback; pi.description = buf; pi.dependencies = KRB5_PLUGIN_NAME L"\0"; LoadString(hResModule, IDS_IDENTPRO_DESC, buf, ARRAYLENGTH(buf)); kmm_provide_plugin(h_module, &pi); if(KHM_FAILED(rv = init_imports())) goto _exit; if(KHM_FAILED(rv = init_error_funcs())) goto _exit; /* Register common data types */ if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ENCTYPE, &type_id_enctype))) { kcdb_type type; kcdb_type *t32; kcdb_type_get_info(KCDB_TYPE_INT32, &t32); type.id = KCDB_TYPE_INVALID; type.name = TYPENAME_ENCTYPE; type.flags = KCDB_TYPE_FLAG_CB_FIXED; type.cb_max = t32->cb_max; type.cb_min = t32->cb_min; type.isValid = t32->isValid; type.comp = t32->comp; type.dup = t32->dup; type.toString = enctype_toString; rv = kcdb_type_register(&type, &type_id_enctype); kcdb_type_release_info(t32); if(KHM_FAILED(rv)) goto _exit; type_regd_enctype = TRUE; } if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ADDR_LIST, &type_id_addr_list))) { kcdb_type type; kcdb_type *tdata; kcdb_type_get_info(KCDB_TYPE_DATA, &tdata); type.id = KCDB_TYPE_INVALID; type.name = TYPENAME_ADDR_LIST; type.flags = KCDB_TYPE_FLAG_CB_MIN; type.cb_min = 0; type.cb_max = 0; type.isValid = tdata->isValid; type.comp = addr_list_comp; type.dup = tdata->dup; type.toString = addr_list_toString; rv = kcdb_type_register(&type, &type_id_addr_list); kcdb_type_release_info(tdata); if(KHM_FAILED(rv)) goto _exit; type_regd_addr_list = TRUE; } if(KHM_FAILED(kcdb_type_get_id(TYPENAME_KRB5_FLAGS, &type_id_krb5_flags))) { kcdb_type type; kcdb_type *t32; kcdb_type_get_info(KCDB_TYPE_INT32, &t32); type.id = KCDB_TYPE_INVALID; type.name = TYPENAME_KRB5_FLAGS; type.flags = KCDB_TYPE_FLAG_CB_FIXED; type.cb_max = t32->cb_max; type.cb_min = t32->cb_min; type.isValid = t32->isValid; type.comp = t32->comp; type.dup = t32->dup; type.toString = krb5flags_toString; rv = kcdb_type_register(&type, &type_id_krb5_flags); kcdb_type_release_info(t32); if(KHM_FAILED(rv)) goto _exit; type_regd_krb5_flags = TRUE; } if (KHM_FAILED(kcdb_type_get_id(TYPENAME_KVNO, &type_id_kvno))) { kcdb_type type; kcdb_type *t32; kcdb_type_get_info(KCDB_TYPE_INT32, &t32); type.id = KCDB_TYPE_INVALID; type.name = TYPENAME_KVNO; type.flags = KCDB_TYPE_FLAG_CB_FIXED; type.cb_max = t32->cb_max; type.cb_min = t32->cb_min; type.isValid = t32->isValid; type.comp = t32->comp; type.dup = t32->dup; type.toString = kvno_toString; rv = kcdb_type_register(&type, &type_id_kvno); kcdb_type_release_info(t32); if (KHM_FAILED(rv)) goto _exit; type_regd_kvno = TRUE; } /* Register common attributes */ if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KEY_ENCTYPE, &attr_id_key_enctype))) { kcdb_attrib attrib; wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; /* although we are loading a long descriptoin, it still fits in the short descriptoin buffer */ ZeroMemory(&attrib, sizeof(attrib)); attrib.name = ATTRNAME_KEY_ENCTYPE; attrib.id = KCDB_ATTR_INVALID; attrib.type = type_id_enctype; attrib.flags = KCDB_ATTR_FLAG_TRANSIENT; LoadString(hResModule, IDS_KEY_ENCTYPE_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); LoadString(hResModule, IDS_KEY_ENCTYPE_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); attrib.short_desc = sbuf; attrib.long_desc = lbuf; rv = kcdb_attrib_register(&attrib, &attr_id_key_enctype); if(KHM_FAILED(rv)) goto _exit; attr_regd_key_enctype = TRUE; } if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_TKT_ENCTYPE, &attr_id_tkt_enctype))) { kcdb_attrib attrib; wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; /* although we are loading a long descriptoin, it still fits in the short descriptoin buffer */ ZeroMemory(&attrib, sizeof(attrib)); attrib.name = ATTRNAME_TKT_ENCTYPE; attrib.id = KCDB_ATTR_INVALID; attrib.type = type_id_enctype; attrib.flags = KCDB_ATTR_FLAG_TRANSIENT; LoadString(hResModule, IDS_TKT_ENCTYPE_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); LoadString(hResModule, IDS_TKT_ENCTYPE_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); attrib.short_desc = sbuf; attrib.long_desc = lbuf; rv = kcdb_attrib_register(&attrib, &attr_id_tkt_enctype); if(KHM_FAILED(rv)) goto _exit; attr_regd_tkt_enctype = TRUE; } if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_ADDR_LIST, &attr_id_addr_list))) { kcdb_attrib attrib; wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; /* although we are loading a long descriptoin, it still fits in the short descriptoin buffer */ ZeroMemory(&attrib, sizeof(attrib)); attrib.name = ATTRNAME_ADDR_LIST; attrib.id = KCDB_ATTR_INVALID; attrib.type = type_id_addr_list; attrib.flags = KCDB_ATTR_FLAG_TRANSIENT; LoadString(hResModule, IDS_ADDR_LIST_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); LoadString(hResModule, IDS_ADDR_LIST_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); attrib.short_desc = sbuf; attrib.long_desc = lbuf; rv = kcdb_attrib_register(&attrib, &attr_id_addr_list); if(KHM_FAILED(rv)) goto _exit; attr_regd_addr_list = TRUE; } if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_FLAGS, &attr_id_krb5_flags))) { kcdb_attrib attrib; wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; /* although we are loading a long descriptoin, it still fits in the short descriptoin buffer */ ZeroMemory(&attrib, sizeof(attrib)); attrib.name = ATTRNAME_KRB5_FLAGS; attrib.id = KCDB_ATTR_INVALID; attrib.type = type_id_krb5_flags; attrib.flags = KCDB_ATTR_FLAG_TRANSIENT; LoadString(hResModule, IDS_KRB5_FLAGS_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); attrib.short_desc = sbuf; attrib.long_desc = NULL; rv = kcdb_attrib_register(&attrib, &attr_id_krb5_flags); if(KHM_FAILED(rv)) goto _exit; attr_regd_krb5_flags = TRUE; } if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_CCNAME, &attr_id_krb5_ccname))) { kcdb_attrib attrib; wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; /* although we are loading a long descriptoin, it still fits in the short descriptoin buffer */ ZeroMemory(&attrib, sizeof(attrib)); attrib.name = ATTRNAME_KRB5_CCNAME; attrib.id = KCDB_ATTR_INVALID; attrib.type = KCDB_TYPE_STRING; attrib.flags = KCDB_ATTR_FLAG_PROPERTY | KCDB_ATTR_FLAG_TRANSIENT; LoadString(hResModule, IDS_KRB5_CCNAME_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); LoadString(hResModule, IDS_KRB5_CCNAME_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); attrib.short_desc = sbuf; attrib.long_desc = lbuf; rv = kcdb_attrib_register(&attrib, &attr_id_krb5_ccname); if(KHM_FAILED(rv)) goto _exit; attr_regd_krb5_ccname = TRUE; } if (KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KVNO, &attr_id_kvno))) { kcdb_attrib attrib; wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; wchar_t lbuf[KCDB_MAXCCH_LONG_DESC]; /* although we are loading a long description, it still fits in the short description buffer */ ZeroMemory(&attrib, sizeof(attrib)); attrib.name = ATTRNAME_KVNO; attrib.id = KCDB_ATTR_INVALID; attrib.type = type_id_kvno; attrib.flags = KCDB_ATTR_FLAG_TRANSIENT; LoadString(hResModule, IDS_KVNO_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); LoadString(hResModule, IDS_KVNO_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); attrib.short_desc = sbuf; attrib.long_desc = lbuf; rv = kcdb_attrib_register(&attrib, &attr_id_kvno); if (KHM_FAILED(rv)) goto _exit; attr_regd_kvno = TRUE; } if (KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_IDFLAGS, &attr_id_krb5_idflags))) { kcdb_attrib attrib; ZeroMemory(&attrib, sizeof(attrib)); attrib.name = ATTRNAME_KRB5_IDFLAGS; attrib.id = KCDB_ATTR_INVALID; attrib.type = KCDB_TYPE_INT32; attrib.flags = KCDB_ATTR_FLAG_PROPERTY | KCDB_ATTR_FLAG_HIDDEN; /* we don't bother localizing these strings since the attribute is hidden. The user will not see these descriptions anyway. */ attrib.short_desc = L"Krb5 ID flags"; attrib.long_desc = L"Kerberos 5 Identity Flags"; rv = kcdb_attrib_register(&attrib, &attr_id_krb5_idflags); if (KHM_FAILED(rv)) goto _exit; attr_regd_krb5_idflags = TRUE; } rv = kmm_get_plugins_config(0, &csp_plugins); if(KHM_FAILED(rv)) goto _exit; rv = khc_load_schema(csp_plugins, schema_krbconfig); if(KHM_FAILED(rv)) goto _exit; rv = khc_open_space(csp_plugins, CSNAME_KRB5CRED, 0, &csp_krbcred); if(KHM_FAILED(rv)) goto _exit; rv = khc_open_space(csp_krbcred, CSNAME_PARAMS, 0, &csp_params); if(KHM_FAILED(rv)) goto _exit; _exit: return rv; }
khm_int32 KHMAPI khm_krb5_find_ccache_for_identity(khm_handle ident, krb5_context *pctx, void * buffer, khm_size * pcbbuf) { krb5_context ctx = 0; krb5_ccache cache = 0; krb5_error_code code; apiCB * cc_ctx = 0; struct _infoNC ** pNCi = NULL; int i; khm_int32 t; wchar_t * ms = NULL; khm_size cb; krb5_timestamp expiration = 0; krb5_timestamp best_match_expiration = 0; char best_match_ccname[256] = ""; khm_handle csp_params = NULL; khm_handle csp_plugins = NULL; if (!buffer || !pcbbuf) return KHM_ERROR_GENERAL; ctx = *pctx; if (!pcc_initialize || !pcc_get_NC_info || !pcc_free_NC_info || !pcc_shutdown) goto _skip_cc_iter; code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL); if (code) goto _exit; code = pcc_get_NC_info(cc_ctx, &pNCi); if (code) goto _exit; for(i=0; pNCi[i]; i++) { if (pNCi[i]->vers != CC_CRED_V5) continue; code = (*pkrb5_cc_resolve)(ctx, pNCi[i]->name, &cache); if (code) continue; /* need a function to check the cache for the identity * and determine if it has valid tickets. If it has * the right identity and valid tickets, store the * expiration time and the cache name. If it has the * right identity but no valid tickets, store the ccache * name and an expiration time of zero. if it does not * have the right identity don't save the name. * * Keep searching to find the best cache available. */ if (KHM_SUCCEEDED(khm_get_identity_expiration_time(ctx, cache, ident, &expiration))) { if ( expiration > best_match_expiration ) { best_match_expiration = expiration; StringCbCopyA(best_match_ccname, sizeof(best_match_ccname), "API:"); StringCbCatA(best_match_ccname, sizeof(best_match_ccname), pNCi[i]->name); expiration = 0; } } if(ctx != NULL && cache != NULL) (*pkrb5_cc_close)(ctx, cache); cache = 0; } _skip_cc_iter: if (KHM_SUCCEEDED(kmm_get_plugins_config(0, &csp_plugins))) { khc_open_space(csp_plugins, L"Krb5Cred\\Parameters", 0, &csp_params); khc_close_space(csp_plugins); csp_plugins = NULL; } #ifdef DEBUG if (csp_params == NULL) { assert(FALSE); } #endif if (csp_params && KHM_SUCCEEDED(khc_read_int32(csp_params, L"MsLsaList", &t)) && t) { code = (*pkrb5_cc_resolve)(ctx, "MSLSA:", &cache); if (code == 0 && cache) { if (KHM_SUCCEEDED(khm_get_identity_expiration_time(ctx, cache, ident, &expiration))) { if ( expiration > best_match_expiration ) { best_match_expiration = expiration; StringCbCopyA(best_match_ccname, sizeof(best_match_ccname), "MSLSA:"); expiration = 0; } } } if (ctx != NULL && cache != NULL) (*pkrb5_cc_close)(ctx, cache); cache = 0; } if (csp_params && khc_read_multi_string(csp_params, L"FileCCList", NULL, &cb) == KHM_ERROR_TOO_LONG && cb > sizeof(wchar_t) * 2) { wchar_t * t; char ccname[MAX_PATH + 6]; ms = PMALLOC(cb); #ifdef DEBUG assert(ms); #endif khc_read_multi_string(csp_params, L"FileCCList", ms, &cb); for(t = ms; t && *t; t = multi_string_next(t)) { StringCchPrintfA(ccname, ARRAYLENGTH(ccname), "FILE:%S", t); code = (*pkrb5_cc_resolve)(ctx, ccname, &cache); if (code) continue; if (KHM_SUCCEEDED(khm_get_identity_expiration_time(ctx, cache, ident, &expiration))) { if ( expiration > best_match_expiration ) { best_match_expiration = expiration; StringCbCopyA(best_match_ccname, sizeof(best_match_ccname), ccname); expiration = 0; } } if (ctx != NULL && cache != NULL) (*pkrb5_cc_close)(ctx, cache); cache = 0; } PFREE(ms); } _exit: if (csp_params) khc_close_space(csp_params); if (pNCi) (*pcc_free_NC_info)(cc_ctx, &pNCi); if (cc_ctx) (*pcc_shutdown)(&cc_ctx); if (best_match_ccname[0]) { if (*pcbbuf = AnsiStrToUnicode((wchar_t *)buffer, *pcbbuf, best_match_ccname)) { *pcbbuf = (*pcbbuf + 1) * sizeof(wchar_t); return KHM_ERROR_SUCCESS; } } return KHM_ERROR_GENERAL; }
/*! \internal \brief Initialize a plugin \note If kmmint_init_plugin() is called on a plugin, then kmmint_exit_plugin() \b must be called for the plugin. \note Should only be called from the context of the registrar thread */ void kmmint_init_plugin(kmm_plugin_i * p) { DWORD dummy; khm_handle csp_plugin = NULL; khm_handle csp_plugins = NULL; khm_int32 t; /* the following will be undone in kmmint_exit_plugin() */ kmm_hold_plugin(kmm_handle_from_plugin(p)); EnterCriticalSection(&cs_kmm); if(p->state != KMM_PLUGIN_STATE_REG && p->state != KMM_PLUGIN_STATE_HOLD) { LeaveCriticalSection(&cs_kmm); goto _exit; } _begin_task(0); _report_mr1(KHERR_NONE, MSG_IP_TASK_DESC, _cstr(p->p.name)); _describe(); if(p->state == KMM_PLUGIN_STATE_HOLD) { /* if this plugin was held, then we already had a hold from the initial attempt to start the plugin. Undo the hold we did a few lines earlier. */ kmm_release_plugin(kmm_handle_from_plugin(p)); /* same for the plugin count for the module. */ #ifdef DEBUG assert(p->flags & KMM_PLUGIN_FLAG_IN_MODCOUNT); #endif p->module->plugin_count--; p->flags &= ~KMM_PLUGIN_FLAG_IN_MODCOUNT; } p->state = KMM_PLUGIN_STATE_PREINIT; kmmint_delist_plugin(p); kmmint_list_plugin(p); LeaveCriticalSection(&cs_kmm); if(KHM_FAILED(kmm_get_plugins_config(0, &csp_plugins))) { _report_mr0(KHERR_ERROR, MSG_IP_GET_CONFIG); p->state = KMM_PLUGIN_STATE_FAIL_UNKNOWN; goto _exit; } if(KHM_FAILED(kmm_get_plugin_config(p->p.name, 0, &csp_plugin))) { if(KHM_FAILED(kmm_register_plugin(&(p->p), 0))) { _report_mr0(KHERR_ERROR, MSG_IP_NOT_REGISTERED); p->state = KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED; goto _exit; } if(KHM_FAILED(kmm_get_plugin_config(p->p.name, 0, &csp_plugin))) { _report_mr0(KHERR_ERROR, MSG_IP_NOT_REGISTERED); p->state = KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED; goto _exit; } } if (KHM_SUCCEEDED(khc_read_int32(csp_plugin, L"Disabled", &t)) && t) { p->flags |= KMM_PLUGIN_FLAG_DISABLED; p->state = KMM_PLUGIN_STATE_FAIL_DISABLED; goto _exit; } #if 0 /*TODO: check the failure count and act accordingly */ if(KHM_SUCCEEDED(khc_read_int32(csp_plugin, L"FailureCount", &t)) && (t > 0)) { } #endif EnterCriticalSection(&cs_kmm); p->n_depends = 0; p->n_unresolved = 0; do { wchar_t * deps = NULL; wchar_t * d; khm_size sz = 0; if(khc_read_multi_string(csp_plugin, L"Dependencies", NULL, &sz) != KHM_ERROR_TOO_LONG) break; deps = PMALLOC(sz); if(KHM_FAILED(khc_read_multi_string(csp_plugin, L"Dependencies", deps, &sz))) { if(deps) PFREE(deps); break; } for(d = deps; d && *d; d = multi_string_next(d)) { kmm_plugin_i * pd; int i; pd = kmmint_get_plugin_i(d); if(pd->state == KMM_PLUGIN_STATE_NONE) { /* the dependant was not previously known */ pd->state = KMM_PLUGIN_STATE_PLACEHOLDER; } for(i=0; i < pd->n_dependants; i++) { if(pd->dependants[i] == p) break; } if(i >= pd->n_dependants) { if( pd->n_dependants >= KMM_MAX_DEPENDANTS ) { /*TODO: handle this gracefully */ RaiseException(1, EXCEPTION_NONCONTINUABLE, 0, NULL); } /* released in kmmint_free_plugin() */ kmm_hold_plugin(kmm_handle_from_plugin(p)); pd->dependants[pd->n_dependants] = p; pd->n_dependants++; } p->n_depends++; if(pd->state != KMM_PLUGIN_STATE_RUNNING) { p->n_unresolved++; } } if(p->n_unresolved > 0) { p->state = KMM_PLUGIN_STATE_HOLD; } PFREE(deps); } while(FALSE); #ifdef DEBUG assert(!(p->flags & KMM_PLUGIN_FLAG_IN_MODCOUNT)); #endif p->flags |= KMM_PLUGIN_FLAG_IN_MODCOUNT; p->module->plugin_count++; LeaveCriticalSection(&cs_kmm); if(p->state == KMM_PLUGIN_STATE_HOLD) { _report_mr1(KHERR_INFO, MSG_IP_HOLD, _dupstr(p->p.name)); goto _exit_post; } kmmint_add_to_plugin_queue(p); p->ht_thread = CreateThread(NULL, 0, kmmint_plugin_broker, (LPVOID) p, CREATE_SUSPENDED, &dummy); p->state = KMM_PLUGIN_STATE_INIT; ResumeThread(p->ht_thread); _exit_post: if(csp_plugin != NULL) khc_close_space(csp_plugin); if(csp_plugins != NULL) khc_close_space(csp_plugins); _report_mr2(KHERR_INFO, MSG_IP_STATE, _dupstr(p->p.name), _int32(p->state)); _end_task(); return; /* jump here if an error condition happens before the plugin broker thread starts and the plugin should be unloaded */ _exit: if(csp_plugin != NULL) khc_close_space(csp_plugin); if(csp_plugins != NULL) khc_close_space(csp_plugins); _report_mr2(KHERR_WARNING, MSG_IP_EXITING, _dupstr(p->p.name), _int32(p->state)); _end_task(); #ifdef ASYNC_PLUGIN_UNLOAD_ON_FAILURE kmm_hold_plugin(kmm_handle_from_plugin(p)); kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_EXIT_PLUGIN, (void *) p); #else kmmint_exit_plugin(p); #endif }
/* Handler for system messages. The only two we handle are KMSG_SYSTEM_INIT and KMSG_SYSTEM_EXIT. */ khm_int32 KHMAPI handle_kmsg_system(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam) { khm_int32 rv = KHM_ERROR_SUCCESS; switch (msg_subtype) { /* This is the first message that will be received by a plugin. We use it to perform initialization operations such as registering any credential types, data types and attributes. */ case KMSG_SYSTEM_INIT: { kcdb_credtype ct; wchar_t short_desc[KCDB_MAXCCH_SHORT_DESC]; wchar_t long_desc[KCDB_MAXCCH_LONG_DESC]; khui_config_node cnode; khui_config_node_reg creg; kcdb_attrib attr; khm_handle csp_plugin = NULL; khm_handle csp_plugins = NULL; #ifdef BUILD_KRBCOMPAT /* If we don't have a Kerberos backend, then we can't * function. */ if (!DelayLoadHeimdal()) { _reportf("Can't initialize a Kerberos backend. LastError=%d", GetLastError()); return KHM_ERROR_NOT_FOUND; } #endif #if KH_VERSION_API < 12 do { khm_version libver; khm_ui_4 apiver; khm_get_lib_version(&libver, &apiver); if (apiver < 7) break; hm_netidmgr = LoadLibrary(NIMDLLNAME); if (hm_netidmgr == NULL) break; #if KH_VERSION_API < 7 pkhui_action_lock = (void (KHMAPI *)(void)) GetProcAddress(hm_netidmgr, API_khui_action_lock); pkhui_action_unlock = (void (KHMAPI *)(void)) GetProcAddress(hm_netidmgr, API_khui_action_unlock); pkhui_refresh_actions = (void (KHMAPI *)(void)) GetProcAddress(hm_netidmgr, API_khui_refresh_actions); pkhui_request_UI_callback = (khm_int32 (KHMAPI *)(khm_ui_callback, void *)) GetProcAddress(hm_netidmgr, API_khui_request_UI_callback); #endif pkhui_cw_get_primary_id = (khm_int32 (KHMAPI *)(khui_new_creds *, khm_handle *)) GetProcAddress(hm_netidmgr, API_khui_cw_get_primary_id); pkhui_cw_get_result = (khm_int32 (KHMAPI *)(khui_new_creds *)) GetProcAddress(hm_netidmgr, API_khui_cw_get_result); pkhui_cw_get_subtype = (khui_nc_subtype (KHMAPI *)(khui_new_creds *)) GetProcAddress(hm_netidmgr, API_khui_cw_get_subtype); pkhui_cw_get_ctx = (khui_action_context * (KHMAPI *)(khui_new_creds *)) GetProcAddress(hm_netidmgr, API_khui_cw_get_ctx); pkcdb_get_resource = (khm_int32 (KHMAPI *)(khm_handle, kcdb_resource_id, khm_int32, khm_int32 *, void *, void *, khm_size *)) GetProcAddress(hm_netidmgr, API_kcdb_get_resource); } while (FALSE); if (pkhui_cw_get_primary_id == NULL) pkhui_cw_get_primary_id = int_khui_cw_get_primary_id; if (pkhui_cw_get_result == NULL) pkhui_cw_get_result = int_khui_cw_get_result; if (pkhui_cw_get_subtype == NULL) pkhui_cw_get_subtype = int_khui_cw_get_subtype; if (pkhui_cw_get_ctx == NULL) pkhui_cw_get_ctx = int_khui_cw_get_ctx; if (pkcdb_get_resource == NULL) pkcdb_get_resource = int_kcdb_get_resource; #endif /* Add the icon now. On NIM v2.x, doing so after tokens were reported may result in a deadlock as we try to switch to the UI thread and the UI thread is blocked on a resource request to this plug-in. */ kca_icon_set_state(NULL); /* First and foremost, we need to register a credential type. */ ZeroMemory(&ct, sizeof(ct)); ct.id = KCDB_CREDTYPE_AUTO; ct.name = MYCREDTYPE_NAMEW; ct.short_desc = short_desc; ct.long_desc = long_desc; short_desc[0] = L'\0'; LoadString(hResModule, IDS_CT_SHORT_DESC, short_desc, ARRAYLENGTH(short_desc)); long_desc[0] = L'\0'; LoadString(hResModule, IDS_CT_LONG_DESC, long_desc, ARRAYLENGTH(long_desc)); ct.icon = NULL; /* We skip the icon for now, but you can assign a handle to an icon here. The icon will be used to represent the credentials type.*/ kmq_create_subscription(plugin_msg_proc, &ct.sub); ct.is_equal = cred_is_equal; rv = kcdb_credtype_register(&ct, &credtype_id); /* We create a global credential set that we use in the plug-in thread. This alleviates the need to create one everytime we need one. Keep in mind that this should only be used in the plug-in thread and should not be touched from the UI thread or any other thread. */ kcdb_credset_create(&g_credset); /* TODO: Perform additional initialization operations. */ /* Register our attributes */ ZeroMemory(&attr, sizeof(attr)); attr.name = ATTRNAME_KCA_AUTHREALM; attr.id = KCDB_ATTR_INVALID; attr.alt_id = KCDB_ATTR_INVALID; attr.flags = 0; attr.type = KCDB_TYPE_STRING; attr.short_desc = short_desc; attr.long_desc = long_desc; attr.compute_cb = NULL; attr.compute_min_cbsize = 0; attr.compute_max_cbsize = 0; LoadString(hResModule, IDS_ATTR_REALM_SHORT_DESC, short_desc, ARRAYLENGTH(short_desc)); LoadString(hResModule, IDS_ATTR_REALM_LONG_DESC, long_desc, ARRAYLENGTH(long_desc)); rv = kcdb_attrib_register(&attr, &attr_id_auth_realm); if (KHM_FAILED(rv)) break; attr.name = ATTRNAME_SUBJECT_EMAIL; LoadString(hResModule, IDS_ATTR_SUBJECT_EMAIL_SHORT_DESC, short_desc, ARRAYLENGTH(short_desc)); LoadString(hResModule, IDS_ATTR_SUBJECT_EMAIL_LONG_DESC, long_desc, ARRAYLENGTH(long_desc)); rv = kcdb_attrib_register(&attr, &attr_id_subj_email); if (KHM_FAILED(rv)) break; attr.name = ATTRNAME_SUBJECT_DISPLAY; LoadString(hResModule, IDS_ATTR_SUBJECT_SHORT_DESC, short_desc, ARRAYLENGTH(short_desc)); LoadString(hResModule, IDS_ATTR_SUBJECT_LONG_DESC, long_desc, ARRAYLENGTH(long_desc)); rv = kcdb_attrib_register(&attr, &attr_id_subj_display); if (KHM_FAILED(rv)) break; attr.name = ATTRNAME_ISSUER_DISPLAY; LoadString(hResModule, IDS_ATTR_ISSUER_SHORT_DESC, short_desc, ARRAYLENGTH(short_desc)); LoadString(hResModule, IDS_ATTR_ISSUER_LONG_DESC, long_desc, ARRAYLENGTH(long_desc)); rv = kcdb_attrib_register(&attr, &attr_id_issuer_display); if (KHM_FAILED(rv)) break; attr.name = ATTRNAME_ISSUER_NAME; attr.flags = KCDB_ATTR_FLAG_HIDDEN; attr.type = KCDB_TYPE_DATA; attr.short_desc = NULL; attr.long_desc = NULL; rv = kcdb_attrib_register(&attr, &attr_id_issuer_name); if (KHM_FAILED(rv)) break; attr.name = ATTRNAME_SERIAL; rv = kcdb_attrib_register(&attr, &attr_id_serial_number); if (KHM_FAILED(rv)) break; /* List the credentials that are already here */ kca_list_creds(); /* Now we register our configuration panels. */ #ifdef GENERAL_CONFIG_PANEL /* This configuration panel is the one that controls general options. We leave the identity specific and identity defaults for other configuration panels. */ ZeroMemory(&creg, sizeof(creg)); short_desc[0] = L'\0'; LoadString(hResModule, IDS_CFG_SHORT_DESC, short_desc, ARRAYLENGTH(short_desc)); long_desc[0] = L'\0'; LoadString(hResModule, IDS_CFG_LONG_DESC, long_desc, ARRAYLENGTH(long_desc)); creg.name = CONFIGNODE_MAIN; creg.short_desc = short_desc; creg.long_desc = long_desc; creg.h_module = hResModule; creg.dlg_template = MAKEINTRESOURCE(IDD_CONFIG); creg.dlg_proc = config_dlgproc; creg.flags = 0; khui_cfg_register(NULL, &creg); #endif /* Now we do the identity specific and identity default configuration panels. "KhmIdentities" is a predefined configuration node under which all the identity spcific configuration is managed. */ if (KHM_FAILED(khui_cfg_open(NULL, L"KhmIdentities", &cnode))) { /* this should always work */ assert(FALSE); rv = KHM_ERROR_NOT_FOUND; break; } /* First the tab panel for defaults for all identities */ ZeroMemory(&creg, sizeof(creg)); short_desc[0] = L'\0'; LoadString(hResModule, IDS_CFG_IDS_SHORT_DESC, short_desc, ARRAYLENGTH(short_desc)); long_desc[0] = L'\0'; LoadString(hResModule, IDS_CFG_IDS_LONG_DESC, long_desc, ARRAYLENGTH(long_desc)); creg.name = CONFIGNODE_ALL_ID; creg.short_desc = short_desc; creg.long_desc = long_desc; creg.h_module = hResModule; creg.dlg_template = MAKEINTRESOURCE(IDD_CONFIG_IDS); creg.dlg_proc = config_ids_dlgproc; creg.flags = KHUI_CNFLAG_SUBPANEL; khui_cfg_register(cnode, &creg); /* Now the panel for per identity configuration */ ZeroMemory(&creg, sizeof(creg)); short_desc[0] = L'\0'; LoadString(hResModule, IDS_CFG_ID_SHORT_DESC, short_desc, ARRAYLENGTH(short_desc)); long_desc[0] = L'\0'; LoadString(hResModule, IDS_CFG_ID_LONG_DESC, long_desc, ARRAYLENGTH(long_desc)); creg.name = CONFIGNODE_PER_ID; creg.short_desc = short_desc; creg.long_desc = long_desc; creg.h_module = hResModule; creg.dlg_template = MAKEINTRESOURCE(IDD_CONFIG_ID); creg.dlg_proc = config_id_dlgproc; creg.flags = KHUI_CNFLAG_SUBPANEL | KHUI_CNFLAG_INSTANCE; khui_cfg_register(cnode, &creg); khui_cfg_release(cnode); /* load the schema */ if (KHM_SUCCEEDED(kmm_get_plugins_config(0, &csp_plugins))) { khc_load_schema(csp_plugins, plugin_schema); khc_close_space(csp_plugins); } /* open the plug-in and parameter configuration spaces */ if (KHM_SUCCEEDED(kmm_get_plugin_config(MYPLUGIN_NAMEW, KHM_FLAG_CREATE, &csp_plugin))) { khc_open_space(csp_plugin, L"Parameters", KHM_FLAG_CREATE, &csp_params); khc_close_space(csp_plugin); } /* try to install the kpkcs11 plugin now */ install_kpkcs11_plugin(); /* register the "KCA Help" menu item, so that we can add the plug-in menu item to the Help menu. */ { khm_handle h_sub = NULL; #if KH_VERSION_API < 7 if (pkhui_action_lock == NULL || pkhui_action_unlock == NULL || pkhui_refresh_actions == NULL || pkhui_request_UI_callback == NULL) goto no_custom_help; #endif kmq_create_subscription(plugin_msg_proc, &h_sub); LoadString(hResModule, IDS_ACTION_KCA_HELP, short_desc, ARRAYLENGTH(short_desc)); LoadString(hResModule, IDS_ACTION_KCA_HELP_TT, long_desc, ARRAYLENGTH(long_desc)); action_id_kca_help = khui_action_create(NULL, short_desc, long_desc, NULL, KHUI_ACTIONTYPE_TRIGGER, h_sub); if (action_id_kca_help != 0) { khm_size s; khm_size i; khui_menu_def * help_menu; khm_boolean refresh = FALSE; khui_action_lock(); help_menu = khui_find_menu(KHUI_MENU_HELP); if (help_menu) { s = khui_menu_get_size(help_menu); for (i=0; i < s; i++) { khui_action_ref * aref; aref = khui_menu_get_action(help_menu, i); if (aref && !(aref->flags & KHUI_ACTIONREF_PACTION) && aref->action == KHUI_ACTION_HELP_INDEX) { khui_menu_insert_action(help_menu, i + 1, action_id_kca_help, 0); refresh = TRUE; break; } } } khui_action_unlock(); if (refresh) khui_refresh_actions(); } #if KH_VERSION_API < 7 no_custom_help: ; #endif } } break; /* This is the last message that will be received by the plugin. */ case KMSG_SYSTEM_EXIT: { khui_config_node cnode; khui_config_node cn_idents; khm_int32 attr_id; kca_remove_icon(); /* It should not be assumed that initialization of the plugin went well at this point since we receive a KMSG_SYSTEM_EXIT even if the initialization failed. */ /* Try to remove the KCA plug-in action from Help menu if it was successfully registered. Also, delete the action. */ if (action_id_kca_help != 0) { khui_menu_def * help_menu; khm_boolean menu_changed = FALSE; khui_action_lock(); help_menu = khui_find_menu(KHUI_MENU_HELP); if (help_menu) { khm_size s; khm_size i; s = khui_menu_get_size(help_menu); for (i=0; i < s; i++) { khui_action_ref * aref = khui_menu_get_action(help_menu, i); if (aref && !(aref->flags & KHUI_ACTIONREF_PACTION) && aref->action == action_id_kca_help) { khui_menu_remove_action(help_menu, i); menu_changed = TRUE; break; } } } khui_action_delete(action_id_kca_help); khui_action_unlock(); if (menu_changed) khui_refresh_actions(); action_id_kca_help = 0; } if (credtype_id != KCDB_CREDTYPE_INVALID) { kcdb_credtype_unregister(credtype_id); credtype_id = KCDB_CREDTYPE_INVALID; } if (g_credset) { kcdb_credset_delete(g_credset); g_credset = NULL; } /* Now unregister any configuration nodes we registered. */ if (KHM_SUCCEEDED(khui_cfg_open(NULL, CONFIGNODE_MAIN, &cnode))) { khui_cfg_remove(cnode); khui_cfg_release(cnode); } if (KHM_SUCCEEDED(khui_cfg_open(NULL, L"KhmIdentities", &cn_idents))) { if (KHM_SUCCEEDED(khui_cfg_open(cn_idents, CONFIGNODE_ALL_ID, &cnode))) { khui_cfg_remove(cnode); khui_cfg_release(cnode); } if (KHM_SUCCEEDED(khui_cfg_open(cn_idents, CONFIGNODE_PER_ID, &cnode))) { khui_cfg_remove(cnode); khui_cfg_release(cnode); } khui_cfg_release(cn_idents); } if (KHM_SUCCEEDED(kcdb_attrib_get_id(ATTRNAME_KCA_AUTHREALM, &attr_id))) kcdb_attrib_unregister(attr_id); if (KHM_SUCCEEDED(kcdb_attrib_get_id(ATTRNAME_SUBJECT_EMAIL, &attr_id))) kcdb_attrib_unregister(attr_id); if (KHM_SUCCEEDED(kcdb_attrib_get_id(ATTRNAME_SUBJECT_DISPLAY, &attr_id))) kcdb_attrib_unregister(attr_id); if (KHM_SUCCEEDED(kcdb_attrib_get_id(ATTRNAME_ISSUER_DISPLAY, &attr_id))) kcdb_attrib_unregister(attr_id); if (KHM_SUCCEEDED(kcdb_attrib_get_id(ATTRNAME_ISSUER_NAME, &attr_id))) kcdb_attrib_unregister(attr_id); if (KHM_SUCCEEDED(kcdb_attrib_get_id(ATTRNAME_SERIAL, &attr_id))) kcdb_attrib_unregister(attr_id); if (csp_params) { khc_close_space(csp_params); csp_params = NULL; } #if KH_VERSION_API < 12 if (hm_netidmgr) FreeLibrary(hm_netidmgr); pkhui_cw_get_primary_id = NULL; #endif #if KH_VERSION_API < 7 pkhui_action_lock = NULL; pkhui_action_unlock = NULL; pkhui_refresh_actions = NULL; pkhui_request_UI_callback = NULL; #endif /* TODO: Perform additional uninitialization operations. */ } break; } return rv; }