Example #1
0
/* 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;
}
Example #2
0
/* 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;
}